Skip to content

Commit e2f902d

Browse files
committed
Add e2e test
1 parent f7615c2 commit e2f902d

File tree

6 files changed

+195
-1
lines changed

6 files changed

+195
-1
lines changed

Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,8 @@ e2e-templates: $(addprefix $(E2E_NO_ARTIFACT_TEMPLATES_DIR)/, \
184184
cluster-template-flatcar.yaml \
185185
cluster-template-k8s-upgrade.yaml \
186186
cluster-template-flatcar-sysext.yaml \
187-
cluster-template-no-bastion.yaml)
187+
cluster-template-no-bastion.yaml \
188+
cluster-template-health-monitor.yaml)
188189
# Currently no templates that require CI artifacts
189190
# $(addprefix $(E2E_TEMPLATES_DIR)/, add-templates-here.yaml) \
190191
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
apiVersion: kustomize.config.k8s.io/v1beta1
2+
kind: Kustomization
3+
4+
resources:
5+
- ../default
6+
7+
patchesStrategicMerge:
8+
- patch-cluster-health-monitor.yaml
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
2+
kind: OpenStackCluster
3+
metadata:
4+
name: "${CLUSTER_NAME}"
5+
spec:
6+
apiServerLoadBalancer:
7+
monitor:
8+
delay: 15
9+
timeout: 10
10+
maxRetries: 3
11+
maxRetriesDown: 2

test/e2e/shared/defaults.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ const (
6060
FlavorFlatcar = "flatcar"
6161
FlavorKubernetesUpgrade = "k8s-upgrade"
6262
FlavorFlatcarSysext = "flatcar-sysext"
63+
FlavorHealthMonitor = "health-monitor"
6364
)
6465

6566
// DefaultScheme returns the default scheme to use for testing.

test/e2e/shared/openstack.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import (
4040
"github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers"
4141
"github.com/gophercloud/gophercloud/v2/openstack/image/v2/images"
4242
"github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/loadbalancers"
43+
"github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/monitors"
4344
"github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/routers"
4445
"github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/groups"
4546
"github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/rules"
@@ -965,6 +966,54 @@ func DumpOpenStackLoadBalancers(e2eCtx *E2EContext, filter loadbalancers.ListOpt
965966
return loadBalancersList, nil
966967
}
967968

969+
// DumpOpenStackLoadBalancerMonitors gets load balancer health monitors.
970+
func DumpOpenStackLoadBalancerMonitors(e2eCtx *E2EContext, filter monitors.ListOpts) ([]monitors.Monitor, error) {
971+
providerClient, clientOpts, _, err := GetTenantProviderClient(e2eCtx)
972+
if err != nil {
973+
_, _ = fmt.Fprintf(GinkgoWriter, "error creating provider client: %s\n", err)
974+
return nil, err
975+
}
976+
977+
loadBalancerClient, err := openstack.NewLoadBalancerV2(providerClient, gophercloud.EndpointOpts{
978+
Region: clientOpts.RegionName,
979+
})
980+
if err != nil {
981+
return nil, fmt.Errorf("error creating load balancer client: %s", err)
982+
}
983+
984+
allPages, err := monitors.List(loadBalancerClient, filter).AllPages(context.TODO())
985+
if err != nil {
986+
return nil, fmt.Errorf("error getting load balancer monitors: %s", err)
987+
}
988+
monitorsList, err := monitors.ExtractMonitors(allPages)
989+
if err != nil {
990+
return nil, fmt.Errorf("error extracting load balancer monitors: %s", err)
991+
}
992+
return monitorsList, nil
993+
}
994+
995+
// GetOpenStackLoadBalancerMonitor gets a specific load balancer health monitor by ID.
996+
func GetOpenStackLoadBalancerMonitor(e2eCtx *E2EContext, monitorID string) (*monitors.Monitor, error) {
997+
providerClient, clientOpts, _, err := GetTenantProviderClient(e2eCtx)
998+
if err != nil {
999+
_, _ = fmt.Fprintf(GinkgoWriter, "error creating provider client: %s\n", err)
1000+
return nil, err
1001+
}
1002+
1003+
loadBalancerClient, err := openstack.NewLoadBalancerV2(providerClient, gophercloud.EndpointOpts{
1004+
Region: clientOpts.RegionName,
1005+
})
1006+
if err != nil {
1007+
return nil, fmt.Errorf("error creating load balancer client: %s", err)
1008+
}
1009+
1010+
monitor, err := monitors.Get(context.TODO(), loadBalancerClient, monitorID).Extract()
1011+
if err != nil {
1012+
return nil, fmt.Errorf("error getting load balancer monitor: %s", err)
1013+
}
1014+
return monitor, nil
1015+
}
1016+
9681017
func GetOpenStackServerConsoleLog(e2eCtx *E2EContext, id string) (string, error) {
9691018
providerClient, clientOpts, _, err := GetTenantProviderClient(e2eCtx)
9701019
if err != nil {

test/e2e/suites/e2e/e2e_test.go

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ import (
3232
"github.com/gophercloud/gophercloud/v2/openstack"
3333
"github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/volumes"
3434
"github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers"
35+
"github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/loadbalancers"
36+
"github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/monitors"
3537
"github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/layer3/routers"
3638
"github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/groups"
3739
"github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/trunks"
@@ -1029,6 +1031,128 @@ var _ = Describe("e2e tests [PR-Blocking]", func() {
10291031
), "OpenStackMachine should be marked not ready with InstanceDeletedReason")
10301032
})
10311033
})
1034+
1035+
Describe("Workload cluster (health monitor)", func() {
1036+
It("should configure load balancer health monitor with custom settings", func(ctx context.Context) {
1037+
shared.Logf("Creating a cluster with custom health monitor configuration")
1038+
clusterName := fmt.Sprintf("cluster-%s", namespace.Name)
1039+
configCluster := defaultConfigCluster(clusterName, namespace.Name)
1040+
configCluster.ControlPlaneMachineCount = ptr.To(int64(1))
1041+
configCluster.WorkerMachineCount = ptr.To(int64(1))
1042+
configCluster.Flavor = shared.FlavorHealthMonitor
1043+
createCluster(ctx, configCluster, clusterResources)
1044+
1045+
openStackCluster, err := shared.ClusterForSpec(ctx, e2eCtx, namespace)
1046+
Expect(err).NotTo(HaveOccurred())
1047+
1048+
Expect(openStackCluster.Spec.APIServerLoadBalancer).ToNot(BeNil())
1049+
Expect(openStackCluster.Spec.APIServerLoadBalancer.Monitor).ToNot(BeNil())
1050+
Expect(openStackCluster.Spec.APIServerLoadBalancer.Monitor.Delay).ToNot(BeNil())
1051+
Expect(openStackCluster.Spec.APIServerLoadBalancer.Monitor.Delay).To(Equal(15))
1052+
Expect(openStackCluster.Spec.APIServerLoadBalancer.Monitor.Timeout).ToNot(BeNil())
1053+
Expect(openStackCluster.Spec.APIServerLoadBalancer.Monitor.Timeout).To(Equal(10))
1054+
Expect(openStackCluster.Spec.APIServerLoadBalancer.Monitor.MaxRetries).ToNot(BeNil())
1055+
Expect(openStackCluster.Spec.APIServerLoadBalancer.Monitor.MaxRetries).To(Equal(3))
1056+
Expect(openStackCluster.Spec.APIServerLoadBalancer.Monitor.MaxRetriesDown).ToNot(BeNil())
1057+
Expect(openStackCluster.Spec.APIServerLoadBalancer.Monitor.MaxRetriesDown).To(Equal(2))
1058+
1059+
shared.Logf("Looking for load balancer for cluster %s", clusterName)
1060+
expectedLBName := fmt.Sprintf("k8s-clusterapi-cluster-%s-%s-kubeapi", namespace.Name, clusterName)
1061+
loadBalancers, err := shared.DumpOpenStackLoadBalancers(e2eCtx, loadbalancers.ListOpts{
1062+
Name: expectedLBName,
1063+
})
1064+
Expect(err).NotTo(HaveOccurred())
1065+
1066+
if len(loadBalancers) == 0 {
1067+
shared.Logf("Load balancer not found by name, trying by tags")
1068+
loadBalancers, err = shared.DumpOpenStackLoadBalancers(e2eCtx, loadbalancers.ListOpts{
1069+
Tags: []string{clusterName},
1070+
})
1071+
Expect(err).NotTo(HaveOccurred())
1072+
}
1073+
Expect(loadBalancers).ToNot(BeEmpty(), "Load balancer should exist for cluster")
1074+
1075+
loadBalancer := loadBalancers[0]
1076+
shared.Logf("Found load balancer %s with ID %s", loadBalancer.Name, loadBalancer.ID)
1077+
1078+
shared.Logf("Looking for health monitors for load balancer %s", loadBalancer.ID)
1079+
monitorList, err := shared.DumpOpenStackLoadBalancerMonitors(e2eCtx, monitors.ListOpts{})
1080+
Expect(err).NotTo(HaveOccurred())
1081+
1082+
expectedMonitorName := fmt.Sprintf("%s-6443", loadBalancer.Name)
1083+
1084+
var clusterMonitor *monitors.Monitor
1085+
for i := range monitorList {
1086+
monitor := &monitorList[i]
1087+
if monitor.Name == expectedMonitorName || strings.Contains(monitor.Name, loadBalancer.Name) {
1088+
clusterMonitor = monitor
1089+
break
1090+
}
1091+
}
1092+
Expect(clusterMonitor).ToNot(BeNil(), "Health monitor should exist for the cluster load balancer")
1093+
1094+
shared.Logf("Found health monitor %s with ID %s", clusterMonitor.Name, clusterMonitor.ID)
1095+
1096+
Expect(clusterMonitor.Delay).To(Equal(15), "Monitor delay should match configured value")
1097+
Expect(clusterMonitor.Timeout).To(Equal(10), "Monitor timeout should match configured value")
1098+
Expect(clusterMonitor.MaxRetries).To(Equal(3), "Monitor maxRetries should match configured value")
1099+
Expect(clusterMonitor.MaxRetriesDown).To(Equal(2), "Monitor maxRetriesDown should match configured value")
1100+
Expect(clusterMonitor.Type).To(Equal("TCP"), "Monitor should be TCP type")
1101+
1102+
shared.Logf("Testing health monitor configuration update")
1103+
openStackCluster, err = shared.ClusterForSpec(ctx, e2eCtx, namespace)
1104+
Expect(err).NotTo(HaveOccurred())
1105+
1106+
updatedCluster := openStackCluster.DeepCopy()
1107+
updatedCluster.Spec.APIServerLoadBalancer.Monitor.Delay = 20
1108+
updatedCluster.Spec.APIServerLoadBalancer.Monitor.MaxRetries = 4
1109+
1110+
Expect(e2eCtx.Environment.BootstrapClusterProxy.GetClient().Update(ctx, updatedCluster)).To(Succeed())
1111+
1112+
Eventually(func() (bool, error) {
1113+
updatedMonitor, err := shared.GetOpenStackLoadBalancerMonitor(e2eCtx, clusterMonitor.ID)
1114+
if err != nil {
1115+
return false, err
1116+
}
1117+
return updatedMonitor.Delay == 20 && updatedMonitor.MaxRetries == 4, nil
1118+
}, e2eCtx.E2EConfig.GetIntervals(specName, "wait-cluster")...).Should(BeTrue(), "Monitor should be updated with new configuration")
1119+
1120+
finalMonitor, err := shared.GetOpenStackLoadBalancerMonitor(e2eCtx, clusterMonitor.ID)
1121+
Expect(err).NotTo(HaveOccurred())
1122+
Expect(finalMonitor.Delay).To(Equal(20), "Monitor delay should be updated")
1123+
Expect(finalMonitor.MaxRetries).To(Equal(4), "Monitor maxRetries should be updated")
1124+
Expect(finalMonitor.Timeout).To(Equal(10), "Monitor timeout should remain unchanged")
1125+
Expect(finalMonitor.MaxRetriesDown).To(Equal(2), "Monitor maxRetriesDown should remain unchanged")
1126+
1127+
shared.Logf("Testing monitor configuration removal and default value reversion")
1128+
openStackCluster, err = shared.ClusterForSpec(ctx, e2eCtx, namespace)
1129+
Expect(err).NotTo(HaveOccurred())
1130+
1131+
clusterWithRemovedMonitor := openStackCluster.DeepCopy()
1132+
clusterWithRemovedMonitor.Spec.APIServerLoadBalancer.Monitor = nil
1133+
if clusterWithRemovedMonitor.Annotations == nil {
1134+
clusterWithRemovedMonitor.Annotations = make(map[string]string)
1135+
}
1136+
clusterWithRemovedMonitor.Annotations["test.e2e/monitor-update"] = fmt.Sprintf("%d", time.Now().Unix())
1137+
Expect(e2eCtx.Environment.BootstrapClusterProxy.GetClient().Update(ctx, clusterWithRemovedMonitor)).To(Succeed())
1138+
1139+
Eventually(func() (bool, error) {
1140+
revertedMonitor, err := shared.GetOpenStackLoadBalancerMonitor(e2eCtx, clusterMonitor.ID)
1141+
if err != nil {
1142+
return false, err
1143+
}
1144+
return revertedMonitor.Delay == 10 && revertedMonitor.Timeout == 5 &&
1145+
revertedMonitor.MaxRetries == 5 && revertedMonitor.MaxRetriesDown == 3, nil
1146+
}, e2eCtx.E2EConfig.GetIntervals(specName, "wait-cluster")...).Should(BeTrue(), "Monitor should revert to all default values when configuration is removed")
1147+
1148+
revertedMonitor, err := shared.GetOpenStackLoadBalancerMonitor(e2eCtx, clusterMonitor.ID)
1149+
Expect(err).NotTo(HaveOccurred())
1150+
Expect(revertedMonitor.Delay).To(Equal(10), "Monitor delay should revert to default value (10)")
1151+
Expect(revertedMonitor.Timeout).To(Equal(5), "Monitor timeout should revert to default value (5)")
1152+
Expect(revertedMonitor.MaxRetries).To(Equal(5), "Monitor maxRetries should revert to default value (5)")
1153+
Expect(revertedMonitor.MaxRetriesDown).To(Equal(3), "Monitor maxRetriesDown should revert to default value (3)")
1154+
})
1155+
})
10321156
})
10331157

10341158
func defaultConfigCluster(clusterName, namespace string) clusterctl.ConfigClusterInput {

0 commit comments

Comments
 (0)