Skip to content

Commit 904c536

Browse files
Merge pull request #1347 from rvanderp3/SPLAT-2051
SPLAT-2051: implement e2e tests for vSphere multi network
2 parents 3eeb288 + f874bfc commit 904c536

File tree

4 files changed

+564
-3
lines changed

4 files changed

+564
-3
lines changed

go.mod

+2-1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ require (
4242
sigs.k8s.io/yaml v1.4.0
4343
)
4444

45+
require github.com/pkg/errors v0.9.1
46+
4547
require (
4648
4d63.com/gocheckcompilerdirectives v1.2.1 // indirect
4749
4d63.com/gochecknoglobals v0.2.1 // indirect
@@ -235,7 +237,6 @@ require (
235237
github.com/opencontainers/selinux v1.11.1 // indirect
236238
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
237239
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
238-
github.com/pkg/errors v0.9.1 // indirect
239240
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
240241
github.com/polyfloyd/go-errorlint v1.7.0 // indirect
241242
github.com/prometheus/client_model v0.6.1 // indirect

pkg/controller/vsphere/util.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ const (
2424
OpenshiftConfigNamespace = "openshift-config"
2525
)
2626

27-
func getInfrastructure(c runtimeclient.Reader) (*configv1.Infrastructure, error) {
27+
// GetInfrastructure retrieves the Infrastructure object from the provided API reader.
28+
// It returns an error if the API reader is nil or if there's an issue fetching the Infrastructure.
29+
func GetInfrastructure(c runtimeclient.Reader) (*configv1.Infrastructure, error) {
2830
if c == nil {
2931
return nil, errors.New("no API reader -- will not fetch infrastructure config")
3032
}
@@ -44,7 +46,7 @@ func getVSphereConfig(c runtimeclient.Reader, configNamespace string) (*vsphere.
4446
return nil, errors.New("no API reader -- will not fetch vSphere config")
4547
}
4648

47-
infra, err := getInfrastructure(c)
49+
infra, err := GetInfrastructure(c)
4850
if err != nil {
4951
return nil, err
5052
}

test/e2e/vsphere/multi-nic.go

+249
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
package vsphere
2+
3+
import (
4+
"context"
5+
_ "embed"
6+
"fmt"
7+
"slices"
8+
"strings"
9+
10+
. "github.com/onsi/ginkgo/v2"
11+
. "github.com/onsi/gomega"
12+
configv1 "github.com/openshift/api/config/v1"
13+
machinev1beta1 "github.com/openshift/api/machine/v1beta1"
14+
configclient "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1"
15+
machinesetclient "github.com/openshift/client-go/machine/clientset/versioned/typed/machine/v1beta1"
16+
"github.com/openshift/machine-api-operator/pkg/controller/vsphere"
17+
e2eutil "github.com/openshift/machine-api-operator/test/e2e"
18+
corev1 "k8s.io/api/core/v1"
19+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
20+
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21+
"k8s.io/client-go/kubernetes"
22+
"k8s.io/client-go/rest"
23+
e2e "k8s.io/kubernetes/test/e2e/framework"
24+
)
25+
26+
func failIfNodeNotInMachineNetwork(nodes corev1.NodeList, machineNetworks []string) {
27+
28+
By("checking if nodes are in the machine network")
29+
30+
for _, node := range nodes.Items {
31+
for _, address := range node.Status.Addresses {
32+
if address.Type != "InternalIP" && address.Type != "ExternalIP" {
33+
continue
34+
}
35+
inRange, err := isIpInCidrRange(address.Address, machineNetworks[0])
36+
Expect(err).NotTo(HaveOccurred())
37+
Expect(inRange).To(BeTrue())
38+
}
39+
}
40+
}
41+
42+
func failIfIncorrectPortgroupsAttachedToVMs(
43+
ctx context.Context,
44+
infra configv1.PlatformSpec,
45+
nodeList *corev1.NodeList,
46+
vsphereCreds *corev1.Secret) {
47+
48+
By("checking if VMs have the correct portgroups attached")
49+
50+
for _, failureDomain := range infra.VSphere.FailureDomains {
51+
nodes, err := getNodesInFailureDomain(infra.VSphere, failureDomain, nodeList)
52+
fmt.Printf("nodes: %d", len(nodes))
53+
Expect(err).NotTo(HaveOccurred())
54+
55+
vmPortgroupMap, err := GetPortGroupsAttachedToVMsInFailureDomain(ctx, failureDomain, vsphereCreds, infra.VSphere.VCenters)
56+
if err != nil {
57+
Expect(err).NotTo(HaveOccurred())
58+
}
59+
60+
var nodeProviderIds []string
61+
for _, node := range nodes {
62+
providerId := node.Spec.ProviderID
63+
Expect(len(providerId)).ShouldNot(BeZero())
64+
65+
parts := strings.Split(providerId, "vsphere://")
66+
Expect(len(parts)).Should(BeIdenticalTo(2))
67+
68+
nodeProviderIds = append(nodeProviderIds, parts[1])
69+
}
70+
71+
for _, nodeProviderId := range nodeProviderIds {
72+
attachedPortgroups, exists := vmPortgroupMap[nodeProviderId]
73+
Expect(exists).To(BeTrue())
74+
75+
slices.Sort(attachedPortgroups)
76+
slices.Sort(failureDomain.Topology.Networks)
77+
if slices.Compare(attachedPortgroups, failureDomain.Topology.Networks) != 0 {
78+
Expect(fmt.Errorf("portgroups for VM %s does not align with failure domain %s", nodeProviderId, failureDomain.Name)).NotTo(HaveOccurred())
79+
}
80+
}
81+
}
82+
}
83+
84+
func failIfNodeNetworkingInconsistentWithMachineNetwork(infra configv1.PlatformSpec, machineNetworks []string) {
85+
internalNodeNetworking := infra.VSphere.NodeNetworking.Internal
86+
externalNodeNetworking := infra.VSphere.NodeNetworking.External
87+
88+
By("comparing nodeNetworking slices to the machine network")
89+
for _, nodeNetworkingSpec := range []configv1.VSpherePlatformNodeNetworkingSpec{internalNodeNetworking, externalNodeNetworking} {
90+
slices.Sort(nodeNetworkingSpec.NetworkSubnetCIDR)
91+
Expect(slices.Equal(nodeNetworkingSpec.NetworkSubnetCIDR, machineNetworks)).To(BeTrue())
92+
}
93+
}
94+
95+
func failIfMachinesDoNotHaveAllPortgroups(platformSpec configv1.PlatformSpec, machines *machinev1beta1.MachineList) {
96+
97+
By("checking to see if machines have all portgroups")
98+
99+
for _, failureDomain := range platformSpec.VSphere.FailureDomains {
100+
machinesInFailureDomain, err := getMachinesInFailureDomain(platformSpec.VSphere, failureDomain, machines)
101+
Expect(err).NotTo(HaveOccurred())
102+
103+
for _, machine := range machinesInFailureDomain {
104+
failIfMachineDoesNotHaveAllPortgroups(machine, failureDomain)
105+
}
106+
}
107+
}
108+
109+
func failIfMachineDoesNotHaveAllPortgroups(machine machinev1beta1.Machine, failureDomain configv1.VSpherePlatformFailureDomainSpec) {
110+
111+
By("checking to see if machine has all portgroups")
112+
113+
spec, err := vsphere.ProviderSpecFromRawExtension(machine.Spec.ProviderSpec.Value)
114+
Expect(err).NotTo(HaveOccurred())
115+
116+
expectedPortgroups := failureDomain.Topology.Networks
117+
var portgroups []string
118+
119+
for _, device := range spec.Network.Devices {
120+
portgroups = append(portgroups, device.NetworkName)
121+
}
122+
123+
slices.Sort(expectedPortgroups)
124+
slices.Sort(portgroups)
125+
126+
Expect(slices.Equal(expectedPortgroups, portgroups)).To(BeTrue())
127+
}
128+
129+
var _ = Describe("[sig-cluster-lifecycle][OCPFeatureGate:VSphereMultiNetworks][platform:vsphere] Managed cluster should", func() {
130+
defer GinkgoRecover()
131+
ctx := context.Background()
132+
133+
var (
134+
cfg *rest.Config
135+
c *kubernetes.Clientset
136+
cc *configclient.ConfigV1Client
137+
138+
mc *machinesetclient.MachineV1beta1Client
139+
err error
140+
machineNetworks []string
141+
infra *configv1.Infrastructure
142+
nodes *corev1.NodeList
143+
machinePortgroups []string
144+
vsphereCreds *corev1.Secret
145+
machines *machinev1beta1.MachineList
146+
)
147+
148+
BeforeEach(func() {
149+
cfg, err = e2e.LoadConfig()
150+
Expect(err).NotTo(HaveOccurred())
151+
c, err = e2e.LoadClientset()
152+
Expect(err).NotTo(HaveOccurred())
153+
mc, err = machinesetclient.NewForConfig(cfg)
154+
Expect(err).NotTo(HaveOccurred())
155+
cc, err = configclient.NewForConfig(cfg)
156+
Expect(err).NotTo(HaveOccurred())
157+
infra, err = cc.Infrastructures().Get(ctx, "cluster", metav1.GetOptions{})
158+
Expect(err).NotTo(HaveOccurred())
159+
160+
vsphereCreds, err = c.CoreV1().Secrets("kube-system").Get(ctx, "vsphere-creds", v1.GetOptions{})
161+
Expect(err).NotTo(HaveOccurred())
162+
163+
Expect(len(infra.Spec.PlatformSpec.VSphere.FailureDomains) >= 1)
164+
165+
for _, machineNetwork := range infra.Spec.PlatformSpec.VSphere.MachineNetworks {
166+
machineNetworks = append(machineNetworks, string(machineNetwork))
167+
}
168+
169+
Expect(len(machineNetworks) >= 1)
170+
slices.Sort(machineNetworks)
171+
172+
nodes, err = c.CoreV1().Nodes().List(ctx, v1.ListOptions{})
173+
Expect(err).NotTo(HaveOccurred())
174+
175+
machines, err = mc.Machines("openshift-machine-api").List(ctx, v1.ListOptions{})
176+
Expect(err).NotTo(HaveOccurred())
177+
178+
portGroups := make(map[string]any)
179+
for _, machine := range machines.Items {
180+
providerSpec, err := vsphere.ProviderSpecFromRawExtension(machine.Spec.ProviderSpec.Value)
181+
Expect(err).NotTo(HaveOccurred())
182+
183+
for _, network := range providerSpec.Network.Devices {
184+
portGroups[network.NetworkName] = network
185+
}
186+
}
187+
188+
for k, _ := range portGroups {
189+
machinePortgroups = append(machinePortgroups, k)
190+
}
191+
})
192+
193+
It("node addresses should be correlated with the machine network", func() {
194+
By("checking for correlation between node internal/external IPs and the machine network")
195+
failIfNodeNotInMachineNetwork(*nodes, machineNetworks)
196+
})
197+
198+
It("machine network should be correlated with node networking", func() {
199+
failIfNodeNetworkingInconsistentWithMachineNetwork(infra.Spec.PlatformSpec, machineNetworks)
200+
})
201+
202+
It("machines should have all specified portgroup associated with their failure domain", func() {
203+
failIfMachinesDoNotHaveAllPortgroups(infra.Spec.PlatformSpec, machines)
204+
})
205+
206+
It("node VMs should have all specified portgroups attached which are associated with their failure domain", func() {
207+
failIfIncorrectPortgroupsAttachedToVMs(ctx, infra.Spec.PlatformSpec, nodes, vsphereCreds)
208+
})
209+
210+
It("new machines should pass multi network tests", func() {
211+
machineSets, err := e2eutil.GetMachineSets(cfg)
212+
Expect(err).NotTo(HaveOccurred())
213+
214+
Expect(len(machineSets.Items) >= 1)
215+
216+
machineSet := machineSets.Items[0]
217+
218+
// scale up new machine and wait for scale up to complete
219+
By("scaling up a new machineset which should have multiple NICs")
220+
err = e2eutil.ScaleMachineSet(cfg, machineSet.Name, int(*machineSet.Spec.Replicas)+1)
221+
Expect(err).NotTo(HaveOccurred())
222+
223+
nodes, err = c.CoreV1().Nodes().List(ctx, v1.ListOptions{})
224+
Expect(err).NotTo(HaveOccurred())
225+
226+
machines, err = mc.Machines("openshift-machine-api").List(ctx, v1.ListOptions{})
227+
Expect(err).NotTo(HaveOccurred())
228+
229+
By("determining common port groups among machines")
230+
portGroups := make(map[string]any)
231+
for _, machine := range machines.Items {
232+
providerSpec, err := vsphere.ProviderSpecFromRawExtension(machine.Spec.ProviderSpec.Value)
233+
Expect(err).NotTo(HaveOccurred())
234+
235+
for _, network := range providerSpec.Network.Devices {
236+
portGroups[network.NetworkName] = network
237+
}
238+
}
239+
240+
for k, _ := range portGroups {
241+
machinePortgroups = append(machinePortgroups, k)
242+
}
243+
244+
failIfNodeNotInMachineNetwork(*nodes, machineNetworks)
245+
failIfNodeNetworkingInconsistentWithMachineNetwork(infra.Spec.PlatformSpec, machineNetworks)
246+
failIfMachinesDoNotHaveAllPortgroups(infra.Spec.PlatformSpec, machines)
247+
failIfIncorrectPortgroupsAttachedToVMs(ctx, infra.Spec.PlatformSpec, nodes, vsphereCreds)
248+
})
249+
})

0 commit comments

Comments
 (0)