Skip to content

Commit e4c628b

Browse files
committed
reabse + update per code review
Signed-off-by: nhamza <[email protected]>
1 parent 1e8e4fa commit e4c628b

File tree

3 files changed

+107
-180
lines changed

3 files changed

+107
-180
lines changed

test/extended/two_node/common.go

Lines changed: 0 additions & 146 deletions
This file was deleted.

test/extended/two_node/tnf_degraded.go

Lines changed: 22 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,19 @@ import (
1111

1212
machineconfigv1 "github.com/openshift/api/machineconfiguration/v1"
1313
machineconfigclient "github.com/openshift/client-go/machineconfiguration/clientset/versioned"
14+
"github.com/openshift/origin/test/extended/two_node/utils"
15+
"github.com/openshift/origin/test/extended/util/image"
1416
appsv1 "k8s.io/api/apps/v1"
1517
corev1 "k8s.io/api/core/v1"
1618
policyv1 "k8s.io/api/policy/v1"
1719
apierrs "k8s.io/apimachinery/pkg/api/errors"
20+
1821
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1922
k8sruntime "k8s.io/apimachinery/pkg/runtime"
2023
"k8s.io/apimachinery/pkg/util/intstr"
2124
"k8s.io/apimachinery/pkg/util/wait"
2225
"k8s.io/client-go/kubernetes"
26+
"k8s.io/utils/ptr"
2327

2428
exutil "github.com/openshift/origin/test/extended/util"
2529
)
@@ -39,10 +43,10 @@ var _ = g.Describe("[sig-apps][OCPFeatureGate:DualReplica][Suite:openshift/two-n
3943
kubeClient := oc.AdminKubeClient()
4044

4145
g.BeforeEach(func() {
42-
ensureTNFDegradedOrSkip(oc)
46+
utils.EnsureTNFDegradedOrSkip(oc)
4347
})
4448

45-
g.It("PDB minAvailable=1 should allow a single eviction and block the second in TNF degraded mode [apigroup:policy]", func() {
49+
g.It("should allow a single eviction and block the second when PDB minAvailable=1 [apigroup:policy]", func() {
4650
ns := oc.Namespace()
4751
labels := map[string]string{pdbLabelKey: pdbLabelValue}
4852
selector := fmt.Sprintf("%s=%s", pdbLabelKey, pdbLabelValue)
@@ -51,7 +55,7 @@ var _ = g.Describe("[sig-apps][OCPFeatureGate:DualReplica][Suite:openshift/two-n
5155
deploy, err := createPauseDeployment(ctx, kubeClient, ns, pdbDeploymentName, 2, labels)
5256
o.Expect(err).NotTo(o.HaveOccurred())
5357

54-
err = waitForDeploymentAvailable(ctx, kubeClient, ns, deploy.Name, 2, 3*time.Minute)
58+
err = exutil.WaitForDeploymentReadyWithTimeout(oc, deploy.Name, ns, -1, 3*time.Minute)
5559
o.Expect(err).NotTo(o.HaveOccurred(), "deployment did not reach 2 available replicas")
5660

5761
// PDB minAvailable=1
@@ -91,12 +95,13 @@ var _ = g.Describe("[sig-apps][OCPFeatureGate:DualReplica][Suite:openshift/two-n
9195
o.Expect(err).NotTo(o.HaveOccurred())
9296
o.Expect(currentPDB.Status.DisruptionsAllowed).To(o.Equal(int32(0)), "expected disruptionsAllowed=0 after second eviction attempt")
9397
})
94-
g.It("should block a reboot-required MachineConfig rollout on the remaining master in TNF degraded mode [Serial] [apigroup:machineconfiguration.openshift.io]", func() {
98+
99+
g.It("should block a reboot-required MachineConfig rollout on the remaining master[Serial] [apigroup:machineconfiguration.openshift.io]", func() {
95100
ns := oc.Namespace()
96101
mcoClient := machineconfigclient.NewForConfigOrDie(oc.AdminConfig())
97102

98-
masterNode, err := getReadyMasterNode(ctx, kubeClient)
99-
o.Expect(err).NotTo(o.HaveOccurred(), "failed to find a Ready master node in TNF degraded mode")
103+
masterNode, err := utils.GetReadyMasterNode(ctx, oc)
104+
o.Expect(err).NotTo(o.HaveOccurred(), "failed to find a Ready master node")
100105

101106
originalBootID := masterNode.Status.NodeInfo.BootID
102107
originalUnschedulable := masterNode.Spec.Unschedulable
@@ -108,7 +113,7 @@ var _ = g.Describe("[sig-apps][OCPFeatureGate:DualReplica][Suite:openshift/two-n
108113
originalConfigName := masterMCP.Status.Configuration.Name
109114

110115
// Create a small reboot-required MachineConfig targeting master
111-
ignFileContents := fmt.Sprintf("TNF degraded reboot-block test namespace=%s", ns)
116+
ignFileContents := fmt.Sprintf(" reboot-block test namespace=%s", ns)
112117

113118
testMC := newMasterRebootRequiredMachineConfig(rebootTestMCName, rebootTestMCFile, ignFileContents)
114119

@@ -128,7 +133,7 @@ var _ = g.Describe("[sig-apps][OCPFeatureGate:DualReplica][Suite:openshift/two-n
128133
)
129134
}()
130135

131-
g.By("observing degraded TNF behavior (node safety + MCP blockage)")
136+
g.By("observing (node safety + MCP blockage)")
132137

133138
observationWindow := 3 * time.Minute
134139

@@ -143,7 +148,7 @@ var _ = g.Describe("[sig-apps][OCPFeatureGate:DualReplica][Suite:openshift/two-n
143148
observationWindow,
144149
)
145150

146-
o.Expect(err).NotTo(o.HaveOccurred(), "TNF degraded behavior was not enforced correctly")
151+
o.Expect(err).NotTo(o.HaveOccurred(), "behavior was not enforced correctly")
147152
})
148153
},
149154
)
@@ -173,8 +178,13 @@ func createPauseDeployment(
173178
Spec: corev1.PodSpec{
174179
Containers: []corev1.Container{
175180
{
176-
Name: "pause",
177-
Image: "registry.k8s.io/pause:3.9",
181+
Name: "busy-work",
182+
Image: image.ShellImage(),
183+
Command: []string{
184+
"/bin/bash",
185+
"-c",
186+
`while true; do echo "Busy working, cycling through the ones and zeros"; sleep 5; done`,
187+
},
178188
},
179189
},
180190
},
@@ -198,7 +208,7 @@ func createPDBMinAvailable(
198208
Namespace: ns,
199209
},
200210
Spec: policyv1.PodDisruptionBudgetSpec{
201-
MinAvailable: intOrStringPtr(intstr.FromInt(minAvailable)),
211+
MinAvailable: ptr.To(intstr.FromInt(minAvailable)),
202212
Selector: &metav1.LabelSelector{
203213
MatchLabels: labels,
204214
},
@@ -207,24 +217,6 @@ func createPDBMinAvailable(
207217
return client.PolicyV1().PodDisruptionBudgets(ns).Create(ctx, pdb, metav1.CreateOptions{})
208218
}
209219

210-
func waitForDeploymentAvailable(
211-
ctx context.Context,
212-
client kubernetes.Interface,
213-
namespace, name string,
214-
desiredAvailable int32,
215-
timeout time.Duration,
216-
) error {
217-
interval := 2 * time.Second
218-
219-
return wait.PollUntilContextTimeout(ctx, interval, timeout, true, func(ctx context.Context) (bool, error) {
220-
dep, err := client.AppsV1().Deployments(namespace).Get(ctx, name, metav1.GetOptions{})
221-
if err != nil {
222-
return false, err
223-
}
224-
return dep.Status.AvailableReplicas >= desiredAvailable, nil
225-
})
226-
}
227-
228220
func waitForPDBDisruptionsAllowed(
229221
ctx context.Context,
230222
client kubernetes.Interface,
@@ -264,10 +256,6 @@ func evictPod(
264256
return client.CoreV1().Pods(pod.Namespace).EvictV1(ctx, eviction)
265257
}
266258

267-
func intOrStringPtr(v intstr.IntOrString) *intstr.IntOrString {
268-
return &v
269-
}
270-
271259
func newMasterRebootRequiredMachineConfig(name, path, contents string) *machineconfigv1.MachineConfig {
272260
encoded := base64.StdEncoding.EncodeToString([]byte(contents))
273261

test/extended/two_node/utils/common.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,16 @@ import (
88
"strings"
99
"time"
1010

11+
g "github.com/onsi/ginkgo/v2"
12+
o "github.com/onsi/gomega"
1113
v1 "github.com/openshift/api/config/v1"
1214
exutil "github.com/openshift/origin/test/extended/util"
1315
corev1 "k8s.io/api/core/v1"
1416
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
17+
1518
"k8s.io/apimachinery/pkg/runtime"
1619
"k8s.io/apimachinery/pkg/util/yaml"
20+
"k8s.io/client-go/kubernetes"
1721
"k8s.io/klog/v2"
1822
nodehelper "k8s.io/kubernetes/test/e2e/framework/node"
1923
e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
@@ -248,3 +252,84 @@ func MonitorClusterOperators(oc *exutil.CLI, timeout time.Duration, pollInterval
248252
time.Sleep(pollInterval)
249253
}
250254
}
255+
256+
// EnsureTNFDegradedOrSkip skips the test if the cluster is not in TNF degraded mode
257+
// (DualReplica topology with exactly one Ready control-plane node).
258+
func EnsureTNFDegradedOrSkip(oc *exutil.CLI) {
259+
SkipIfNotTopology(oc, v1.DualReplicaTopologyMode)
260+
261+
ctx := context.Background()
262+
kubeClient := oc.AdminKubeClient()
263+
264+
masters, err := ListControlPlaneNodes(ctx, kubeClient)
265+
o.Expect(err).NotTo(o.HaveOccurred(), "failed to list control-plane nodes")
266+
267+
if len(masters) != 2 {
268+
g.Skip(fmt.Sprintf(
269+
"TNF degraded tests expect exactly 2 control-plane nodes, found %d",
270+
len(masters),
271+
))
272+
}
273+
274+
readyCount := CountReadyNodes(masters)
275+
if readyCount != 1 {
276+
g.Skip(fmt.Sprintf(
277+
"cluster is not in TNF degraded mode (expected exactly 1 Ready master, got %d)",
278+
readyCount,
279+
))
280+
}
281+
}
282+
283+
// ListControlPlaneNodes returns all nodes labeled as control-plane or master.
284+
func ListControlPlaneNodes(ctx context.Context, client kubernetes.Interface) ([]corev1.Node, error) {
285+
nodes, err := client.CoreV1().Nodes().List(ctx, metav1.ListOptions{
286+
LabelSelector: "node-role.kubernetes.io/master",
287+
})
288+
if err != nil {
289+
return nil, err
290+
}
291+
if len(nodes.Items) > 0 {
292+
return nodes.Items, nil
293+
}
294+
295+
nodes, err = client.CoreV1().Nodes().List(ctx, metav1.ListOptions{
296+
LabelSelector: "node-role.kubernetes.io/control-plane",
297+
})
298+
if err != nil {
299+
return nil, err
300+
}
301+
return nodes.Items, nil
302+
}
303+
304+
// CountReadyNodes returns the number of nodes in Ready state.
305+
func CountReadyNodes(nodes []corev1.Node) int {
306+
ready := 0
307+
for _, n := range nodes {
308+
for _, cond := range n.Status.Conditions {
309+
if cond.Type == corev1.NodeReady && cond.Status == corev1.ConditionTrue {
310+
ready++
311+
break
312+
}
313+
}
314+
}
315+
return ready
316+
}
317+
318+
// GetReadyMasterNode returns the first Ready control-plane node.
319+
func GetReadyMasterNode(
320+
ctx context.Context,
321+
oc *exutil.CLI,
322+
) (*corev1.Node, error) {
323+
nodes, err := ListControlPlaneNodes(ctx, oc.AdminKubeClient())
324+
if err != nil {
325+
return nil, err
326+
}
327+
for i := range nodes {
328+
node := &nodes[i]
329+
if IsNodeReady(oc, node.Name) {
330+
return node, nil
331+
}
332+
}
333+
334+
return nil, fmt.Errorf("no Ready master node found")
335+
}

0 commit comments

Comments
 (0)