-
Notifications
You must be signed in to change notification settings - Fork 211
NO-ISSUE: OTA-1605 Create first e2e test OCP-42543 #1249
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
a6a8ada to
37caff4
Compare
a79646a to
d944000
Compare
|
Please note that
|
d944000 to
067cd4b
Compare
|
@JianLi-RH: This pull request explicitly references no jira issue. In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
|
Tested on my local machine: Run the case: |
067cd4b to
bac7793
Compare
|
/cc |
|
/cc |
.openshift-tests-extension/openshift_payload_cluster-version-operator.json
Show resolved
Hide resolved
bac7793 to
51facb3
Compare
|
After modification, the case is still valid: |
51facb3 to
8e9da36
Compare
.openshift-tests-extension/openshift_payload_cluster-version-operator.json
Outdated
Show resolved
Hide resolved
72354d1 to
3a8631b
Compare
@JianLi-RH, in case the investigation is not done by the end of the day, you want simply more time to explore or are simply busy, I would like to ask you whether it would be fine for me to rename the sanity test in a separate PR. That specific change is blocking my openshift/origin#30316 PR. I am happy to rename the test personally in a separate PR to unblock my PR while we are working on this one. |
|
@DavidHurta of course, go ahead, please. I am not sure when I can finish the investigation. |
d2300d9 to
f98e03c
Compare
|
/unhold |
Clientset instance can be used to connect to cluster, manage resources. With clientset instance we can evaluate the posibility of moving other tests to OTE. The reference to OTE framework: https://docs.google.com/document/d/1cFZj9QdzW8hbHc3H0Nce-2xrJMtpDJrwAse9H7hLiWk/edit?tab=t.0#heading=h.8cf3f4eii1q8
878cbc8 to
1102f9c
Compare
|
@hongkailiu @DavidHurta Just added back the case, please help review it. Here is the output: $ ginkgo ./test/...
Running Suite: CVO Suite - /home/jianl/1_code/cluster-version-operator/test/cvo
===============================================================================
Random Seed: 1763353592
Will run 2 of 2 specs
•Test Authentication...
namespace: default
- Test services...
- Test RoleBinding...
- Test CronJob...
success
namespace: kube-node-lease
- Test services...
- Test RoleBinding...
- Test CronJob...
success
namespace: kube-public
- Test services...
- Test RoleBinding...
- Test CronJob...
.....................
namespace: openshift-vsphere-infra
- Test services...
- Test RoleBinding...
- Test CronJob...
success
•
Ran 2 of 2 Specs in 82.840 seconds
SUCCESS! -- 2 Passed | 0 Failed | 0 Pending | 0 Skipped
PASS
Ginkgo ran 1 suite in 1m24.112444203s
Test Suite PassedIf there is resource installed unexpected, it will fail as below: $ ginkgo ./test/...
Running Suite: CVO Suite - /home/jianl/1_code/cluster-version-operator/test/cvo
===============================================================================
Random Seed: 1763353871
Will run 2 of 2 specs
•Test Authentication...
------------------------------
• [FAILED] [1.522 seconds]
[Jira:"Cluster Version Operator"] cluster-version-operator-tests [It] should not install resources annotated with release.openshift.io/delete=true [cvo, Conformance, High, 42543]
/home/jianl/1_code/cluster-version-operator/test/cvo/cvo.go:20
[FAILED] Unexpectedly installed authentication cluster which has release.openshift.io/delete annotation
Expected
<bool>: true
not to be true
In [It] at: /home/jianl/1_code/cluster-version-operator/test/cvo/cvo.go:30 @ 11/17/25 12:31:14.175
------------------------------
Summarizing 1 Failure:
[FAIL] [Jira:"Cluster Version Operator"] cluster-version-operator-tests [It] should not install resources annotated with release.openshift.io/delete=true [cvo, Conformance, High, 42543]
/home/jianl/1_code/cluster-version-operator/test/cvo/cvo.go:30
Ran 2 of 2 Specs in 1.522 seconds
FAIL! -- 1 Passed | 1 Failed | 0 Pending | 0 Skipped
--- FAIL: TestGinkgo (1.52s)
FAIL
Ginkgo ran 1 suite in 2.725034617s
Test Suite Failed |
1102f9c to
cc98b16
Compare
cc98b16 to
c168996
Compare
…ient-go openshift/client-go gives us more efficient functions to access cluster
c168996 to
e35f937
Compare
After adding new OTE test cases, we need to update test metadata
4dbdb2c to
946876f
Compare
WalkthroughAdds a new CVO test entry and implements a Ginkgo v2 CVO test suite that validates resources annotated Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting
📒 Files selected for processing (3)
.openshift-tests-extension/openshift_payload_cluster-version-operator.json(1 hunks)test/cvo/cvo.go(1 hunks)test/utilities/connection.go(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**
⚙️ CodeRabbit configuration file
-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.
Files:
test/utilities/connection.gotest/cvo/cvo.go
🧬 Code graph analysis (1)
test/cvo/cvo.go (1)
test/utilities/connection.go (2)
MustGetV1Client(65-71)MustGetKubeClient(56-62)
🔇 Additional comments (3)
.openshift-tests-extension/openshift_payload_cluster-version-operator.json (1)
13-25: New test metadata entry looks consistent and well-formedThe added metadata object matches the existing structure (name, labels, resources, source, lifecycle, environmentSelector) and aligns with the new CVO test and label conventions (42543, Conformance, High, cvo). No issues from a structure/maintainability perspective.
test/utilities/connection.go (1)
1-71: Client helper utilities are correct and suitable for test usageKUBECONFIG handling, config construction, clientset creation, and error wrapping all look correct. The
MustGet*helpers are appropriate for tests where a missing/invalid config should hard-fail immediately. No blocking issues here.test/cvo/cvo.go (1)
17-21: Sanity test Describe block is fineThe lightweight
[Jira:"Cluster Version Operator"] cluster-version-operator-testssanity spec is simple and effective as an integration signal. No issues.
| var _ = g.Describe("[Jira:Cluster Version Operator] The cluster version operator", g.Ordered, g.Label("cvo"), func() { | ||
| defer g.GinkgoRecover() | ||
| var client *v1.ConfigV1Client | ||
| var kubeclient *kubernetes.Clientset | ||
|
|
||
| g.BeforeAll(func() { | ||
| client = utilities.MustGetV1Client() | ||
| kubeclient = utilities.MustGetKubeClient() | ||
| }) | ||
|
|
||
| g.It(`should not install resources annotated with release.openshift.io/delete=true`, g.Label("Conformance", "High", "42543"), func() { | ||
| annotation := "release.openshift.io/delete" | ||
|
|
||
| auths, err := client.Authentications().List(context.TODO(), metav1.ListOptions{}) | ||
| o.Expect(kerrors.IsNotFound(err)).To(o.BeFalse(), "The NotFound error should occur when listing authentications") | ||
|
|
||
| g.By(fmt.Sprintf("checking if authentication with %s annotation exists", annotation)) | ||
| for _, auth := range auths.Items { | ||
| if _, ok := auth.Annotations[annotation]; ok { | ||
| o.Expect(ok).NotTo(o.BeTrue(), fmt.Sprintf("Unexpectedly installed authentication %s which has '%s' annotation", auth.Name, annotation)) | ||
| } | ||
| } | ||
|
|
||
| namespaces, err := kubeclient.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{}) | ||
| o.Expect(kerrors.IsNotFound(err)).To(o.BeFalse(), "The NotFound error should occur when listing namespaces") | ||
|
|
||
| g.By(fmt.Sprintf("checking if special resources with %s annotation exist in all namespaces", annotation)) | ||
| for _, ns := range namespaces.Items { | ||
| namespace := ns.Name | ||
| fmt.Printf("namespace: %s\n", namespace) | ||
|
|
||
| fmt.Println(" - Test services...") | ||
| services, err := kubeclient.CoreV1().Services(namespace).List(context.TODO(), metav1.ListOptions{}) | ||
| o.Expect(kerrors.IsNotFound(err)).To(o.BeFalse(), "The NotFound error should occur when listing services") | ||
| for _, service := range services.Items { | ||
| if _, ok := service.Annotations[annotation]; ok { | ||
| o.Expect(ok).NotTo(o.BeTrue(), fmt.Sprintf("Unexpectedly installed service %s which has '%s' annotation", service.Name, annotation)) | ||
| } | ||
| } | ||
|
|
||
| fmt.Println(" - Test RoleBinding...") | ||
| rolebindings, err := kubeclient.RbacV1().RoleBindings(namespace).List(context.TODO(), metav1.ListOptions{}) | ||
| o.Expect(kerrors.IsNotFound(err)).To(o.BeFalse(), "The NotFound error should occur when listing rolebindings") | ||
| for _, rb := range rolebindings.Items { | ||
| if _, ok := rb.Annotations[annotation]; ok { | ||
| o.Expect(ok).NotTo(o.BeTrue(), fmt.Sprintf("Unexpectedly installed RoleBinding %s which has '%s' annotation", rb.Name, annotation)) | ||
| } | ||
| } | ||
|
|
||
| fmt.Println(" - Test CronJob...") | ||
| cronjobs, err := kubeclient.BatchV1().CronJobs(namespace).List(context.TODO(), metav1.ListOptions{}) | ||
| o.Expect(kerrors.IsNotFound(err)).To(o.BeFalse(), "The NotFound error should occur when listing cronjobs") | ||
| for _, cj := range cronjobs.Items { | ||
| if _, ok := cj.Annotations[annotation]; ok { | ||
| o.Expect(ok).NotTo(o.BeTrue(), fmt.Sprintf("Unexpectedly installed CronJob %s which has %s annotation", cj.Name, annotation)) | ||
| } | ||
| } | ||
|
|
||
| fmt.Println("success") | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Fix List error handling to fail on real API errors, not just NotFound
All the List calls currently do:
auths, err := client.Authentications().List(...)
o.Expect(kerrors.IsNotFound(err)).To(o.BeFalse(), "The NotFound error should occur when listing ...")This has two problems:
-
False positives on failures
- Any non-
NotFounderror (e.g., auth, RBAC, networking, API server issues) makeskerrors.IsNotFound(err)returnfalse, so the expectation passes. - The test then proceeds, typically iterating over an empty/zero-valued list, and can still pass even though the underlying List failed.
- That means the test can report success while not actually verifying the cluster state.
- Any non-
-
Misleading messages
- The description says “The NotFound error should occur when listing …” while the matcher asserts
BeFalse(), which is contradictory.
- The description says “The NotFound error should occur when listing …” while the matcher asserts
You want the test to fail on any error from those List calls. A more robust pattern is to assert on err directly, for each List:
- auths, err := client.Authentications().List(context.TODO(), metav1.ListOptions{})
- o.Expect(kerrors.IsNotFound(err)).To(o.BeFalse(), "The NotFound error should occur when listing authentications")
+ auths, err := client.Authentications().List(context.TODO(), metav1.ListOptions{})
+ o.Expect(err).NotTo(o.HaveOccurred(), "failed to list authentications")
- namespaces, err := kubeclient.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{})
- o.Expect(kerrors.IsNotFound(err)).To(o.BeFalse(), "The NotFound error should occur when listing namespaces")
+ namespaces, err := kubeclient.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{})
+ o.Expect(err).NotTo(o.HaveOccurred(), "failed to list namespaces")
- services, err := kubeclient.CoreV1().Services(namespace).List(context.TODO(), metav1.ListOptions{})
- o.Expect(kerrors.IsNotFound(err)).To(o.BeFalse(), "The NotFound error should occur when listing services")
+ services, err := kubeclient.CoreV1().Services(namespace).List(context.TODO(), metav1.ListOptions{})
+ o.Expect(err).NotTo(o.HaveOccurred(), "failed to list services")
- rolebindings, err := kubeclient.RbacV1().RoleBindings(namespace).List(context.TODO(), metav1.ListOptions{})
- o.Expect(kerrors.IsNotFound(err)).To(o.BeFalse(), "The NotFound error should occur when listing rolebindings")
+ rolebindings, err := kubeclient.RbacV1().RoleBindings(namespace).List(context.TODO(), metav1.ListOptions{})
+ o.Expect(err).NotTo(o.HaveOccurred(), "failed to list rolebindings")
- cronjobs, err := kubeclient.BatchV1().CronJobs(namespace).List(context.TODO(), metav1.ListOptions{})
- o.Expect(kerrors.IsNotFound(err)).To(o.BeFalse(), "The NotFound error should occur when listing cronjobs")
+ cronjobs, err := kubeclient.BatchV1().CronJobs(namespace).List(context.TODO(), metav1.ListOptions{})
+ o.Expect(err).NotTo(o.HaveOccurred(), "failed to list cronjobs")This way, any failure to talk to the API (including NotFound on the resource type) will correctly fail the spec instead of silently passing.
If you want to double‑check semantics, please confirm in the Kubernetes/client-go docs (or local experiments) that List should normally return an empty list with err == nil when no items exist, and that kerrors.IsNotFound is intended for handling Get/Delete style operations rather than normal successful Lists.
🌐 Web query:
How does the Kubernetes client-go List API signal errors vs. an empty result, and when is k8s.io/apimachinery/pkg/api/errors.IsNotFound typically used?
💡 Result:
Short answer: List returns an empty list with err == nil (the returned List object's Items slice is just empty). IsNotFound is not used for a successful List — it's used when an operation asking for a specific named resource (e.g., Get or Delete by name) returns HTTP 404; k8s.io/apimachinery/pkg/api/errors.IsNotFound(err) detects that 404 StatusError. Use IsNotFound when you expect a single resource might not exist and you want to handle "resource missing" specially.
References: k8s error helpers (IsNotFound). [1] Client List/Get semantics (List returns list object; Reader/List returns error only on failure). [2] REST practice: collection endpoints return 200 + empty array when no items. [3]
Sources:
[1] k8s.io/apimachinery/pkg/api/errors (IsNotFound description).
[2] sigs.k8s.io/controller-runtime/pkg/client (Client.List / Reader semantics).
[3] RESTful API design discussion (return 200 with empty array for empty collections).
Replace error assertions with proper nil checks for all List calls
The web search confirms your analysis: Kubernetes List operations return an empty list with err == nil on success. The IsNotFound check is not intended for List operations—it detects HTTP 404 on named-resource operations (Get/Delete), not on collection endpoints.
This means the current code has a critical flaw:
o.Expect(kerrors.IsNotFound(err)).To(o.BeFalse(), "The NotFound error should occur when listing ...")—will pass whenever IsNotFound(err) == false, which includes:
- Normal success with no items ✓
- Network/auth/RBAC failures ✗ (silent pass when should fail)
Your proposed fix is correct. Replace all five List error checks in test/cvo/cvo.go (lines 26–27, 41–42, 51–52, 60–61, 68–69) with:
-o.Expect(kerrors.IsNotFound(err)).To(o.BeFalse(), "The NotFound error should occur when listing ...")
+o.Expect(err).NotTo(o.HaveOccurred(), "failed to list ...")This ensures any API failure is caught, not silently suppressed.
🤖 Prompt for AI Agents
In test/cvo/cvo.go around lines 23 to 82, the List() error checks use
kerrors.IsNotFound(err) which is inappropriate for collection endpoints and can
silently ignore real API errors; replace each usage at lines ~26–27, ~41–42,
~51–52, ~60–61, and ~68–69 with a direct nil-check assertion (i.e., assert err
is nil) so any List failure causes the test to fail; keep the existing
descriptive messages but change the assertion to ensure err == nil.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (1)
test/cvo/cvo.go (1)
88-138: Fix incorrect error handling for all List operations.As flagged in a previous review, lines 92, 102, 111, 120, and 129 all use
kerrors.IsNotFound(err)incorrectly for List operations. This causes the test to silently pass when List calls fail due to network, authentication, or RBAC issues, creating false positives.Kubernetes List operations return an empty list with
err == nilon success.IsNotFoundis only appropriate for Get/Delete operations on specific named resources.Replace all five error checks with direct nil assertions:
auths, err := client.Authentications().List(context.TODO(), metav1.ListOptions{}) - o.Expect(kerrors.IsNotFound(err)).To(o.BeFalse(), "The NotFound error should occur when listing authentications") + o.Expect(err).NotTo(o.HaveOccurred(), "failed to list authentications") namespaces, err := kubeclient.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{}) - o.Expect(kerrors.IsNotFound(err)).To(o.BeFalse(), "The NotFound error should occur when listing namespaces") + o.Expect(err).NotTo(o.HaveOccurred(), "failed to list namespaces") services, err := kubeclient.CoreV1().Services(namespace).List(context.TODO(), metav1.ListOptions{}) - o.Expect(kerrors.IsNotFound(err)).To(o.BeFalse(), "The NotFound error should occur when listing services") + o.Expect(err).NotTo(o.HaveOccurred(), "failed to list services") rolebindings, err := kubeclient.RbacV1().RoleBindings(namespace).List(context.TODO(), metav1.ListOptions{}) - o.Expect(kerrors.IsNotFound(err)).To(o.BeFalse(), "The NotFound error should occur when listing rolebindings") + o.Expect(err).NotTo(o.HaveOccurred(), "failed to list rolebindings") cronjobs, err := kubeclient.BatchV1().CronJobs(namespace).List(context.TODO(), metav1.ListOptions{}) - o.Expect(kerrors.IsNotFound(err)).To(o.BeFalse(), "The NotFound error should occur when listing cronjobs") + o.Expect(err).NotTo(o.HaveOccurred(), "failed to list cronjobs")
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting
📒 Files selected for processing (1)
test/cvo/cvo.go(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**
⚙️ CodeRabbit configuration file
-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.
Files:
test/cvo/cvo.go
🧬 Code graph analysis (1)
test/cvo/cvo.go (1)
test/utilities/connection.go (2)
MustGetV1Client(65-71)MustGetKubeClient(56-62)
🔇 Additional comments (4)
test/cvo/cvo.go (4)
3-27: LGTM: Import organization is clean.The imports are well-organized with named aliases for Ginkgo and Gomega, and local packages appropriately placed at the end.
72-76: LGTM: Sanity test provides integration signal.This simple test validates the test framework integration and provides a useful signal when troubleshooting OTE issues, as discussed in past reviews.
78-86: LGTM: Test suite setup is correct.The suite properly uses
g.OrderedwithBeforeAllto initialize clients once for all tests, and the labels follow OpenShift testing conventions.
234-234: Update CreateServiceAccount call after fixing the helper function.After applying the fixes to
CreateServiceAccount(removing the unusedclusterRoleparameter), this call needs to be updated. Additionally, the error return value should be checked.- token, _ := CreateServiceAccount(kubeclient, "monitorer", "cluster-admin", ns) + token, err := CreateServiceAccount(kubeclient, "monitorer", ns) + o.Expect(err).NotTo(o.HaveOccurred(), "failed to create service account")
| func CreateServiceAccount(client *kubernetes.Clientset, accountName string, clusterRole string, namespace string) (token string, err error) { | ||
|
|
||
| _, err = client.CoreV1().ServiceAccounts(namespace).Get(context.TODO(), accountName, metav1.GetOptions{}) | ||
|
|
||
| if err == nil { | ||
| token, err := client.CoreV1().ServiceAccounts(namespace).CreateToken(context.TODO(), accountName, &authenticationv1.TokenRequest{}, metav1.CreateOptions{}) | ||
| return token.String(), err | ||
| } | ||
|
|
||
| account := &corev1.ServiceAccount{ | ||
| ObjectMeta: metav1.ObjectMeta{ | ||
| Name: accountName, | ||
| Namespace: namespace, | ||
| }, | ||
| } | ||
| _, err = client.CoreV1().ServiceAccounts(namespace).Create(context.TODO(), account, metav1.CreateOptions{}) | ||
| o.Expect(err).NotTo(o.HaveOccurred()) | ||
|
|
||
| rb := &rbacv1.ClusterRoleBinding{ | ||
| ObjectMeta: metav1.ObjectMeta{ | ||
| Name: "admin", | ||
| Namespace: namespace, | ||
| }, | ||
| RoleRef: rbacv1.RoleRef{ | ||
| APIGroup: "rbac.authorization.k8s.io", | ||
| Kind: "ClusterRole", | ||
| Name: "cluster-admin", | ||
| }, | ||
| Subjects: []rbacv1.Subject{ | ||
| { | ||
| Kind: "ServiceAccount", | ||
| Name: accountName, | ||
| Namespace: namespace, | ||
| }, | ||
| }, | ||
| } | ||
| _, err = client.RbacV1().ClusterRoleBindings().Create(context.TODO(), rb, metav1.CreateOptions{}) | ||
| o.Expect(err).NotTo(o.HaveOccurred()) | ||
|
|
||
| newToken, err := client.CoreV1().ServiceAccounts(namespace).CreateToken(context.TODO(), accountName, &authenticationv1.TokenRequest{}, metav1.CreateOptions{}) | ||
| return newToken.String(), err | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix multiple issues in CreateServiceAccount helper.
This function has several problems:
- Parameter
clusterRoleis unused – the function always binds to"cluster-admin"(line 55), making the parameter misleading. - Name collision risk – ClusterRoleBinding name is hardcoded as
"admin"(line 49), which will cause conflicts if this function is called multiple times with different service accounts. - Invalid namespace field – ClusterRoleBindings are cluster-scoped; setting
Namespace(line 50) has no effect and is misleading. - Type error –
token.String()(lines 35, 69) is invalid;TokenRequestdoesn't have aString()method. You likely wanttoken.Status.Token. - Inconsistent error handling – Using
o.Expect(lines 45, 66) inside a function that returnserrormixes panic-on-failure with explicit error returns.
Apply this diff to fix the issues:
-func CreateServiceAccount(client *kubernetes.Clientset, accountName string, clusterRole string, namespace string) (token string, err error) {
+func CreateServiceAccount(client *kubernetes.Clientset, accountName string, namespace string) (token string, err error) {
_, err = client.CoreV1().ServiceAccounts(namespace).Get(context.TODO(), accountName, metav1.GetOptions{})
if err == nil {
- token, err := client.CoreV1().ServiceAccounts(namespace).CreateToken(context.TODO(), accountName, &authenticationv1.TokenRequest{}, metav1.CreateOptions{})
- return token.String(), err
+ tokenReq, err := client.CoreV1().ServiceAccounts(namespace).CreateToken(context.TODO(), accountName, &authenticationv1.TokenRequest{}, metav1.CreateOptions{})
+ if err != nil {
+ return "", err
+ }
+ return tokenReq.Status.Token, nil
}
account := &corev1.ServiceAccount{
@@ -42,11 +44,13 @@
},
}
_, err = client.CoreV1().ServiceAccounts(namespace).Create(context.TODO(), account, metav1.CreateOptions{})
- o.Expect(err).NotTo(o.HaveOccurred())
+ if err != nil {
+ return "", err
+ }
rb := &rbacv1.ClusterRoleBinding{
ObjectMeta: metav1.ObjectMeta{
- Name: "admin",
- Namespace: namespace,
+ Name: fmt.Sprintf("%s-cluster-admin-binding", accountName),
},
RoleRef: rbacv1.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
@@ -63,8 +67,12 @@
},
}
_, err = client.RbacV1().ClusterRoleBindings().Create(context.TODO(), rb, metav1.CreateOptions{})
- o.Expect(err).NotTo(o.HaveOccurred())
+ if err != nil {
+ return "", err
+ }
- newToken, err := client.CoreV1().ServiceAccounts(namespace).CreateToken(context.TODO(), accountName, &authenticationv1.TokenRequest{}, metav1.CreateOptions{})
- return newToken.String(), err
+ tokenReq, err := client.CoreV1().ServiceAccounts(namespace).CreateToken(context.TODO(), accountName, &authenticationv1.TokenRequest{}, metav1.CreateOptions{})
+ if err != nil {
+ return "", err
+ }
+ return tokenReq.Status.Token, nil
}🤖 Prompt for AI Agents
In test/cvo/cvo.go around lines 29 to 70, fix CreateServiceAccount so it uses
the clusterRole parameter, returns errors instead of calling o.Expect, avoids
hardcoded/duplicated ClusterRoleBinding names, removes the Namespace field from
the cluster-scoped ClusterRoleBinding metadata, and accesses the token string
via token.Status.Token (not token.String()). Specifically: change the
ClusterRoleBinding RoleRef.Name to use the clusterRole param, generate a unique
binding name (e.g. based on accountName and clusterRole) instead of "admin",
omit the Namespace field from the binding metadata, update both token retrievals
to return token.Status.Token, and replace o.Expect checks with proper error
checks and early returns so the function consistently returns (token, err) on
failure.
| g.It(`Precheck with oc adm upgrade recommend`, g.Label("Conformance", "Low", "70980"), func() { | ||
|
|
||
| g.By("create a namespace") | ||
| ns := "ns-70980" | ||
| tmpNs := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}} | ||
| kubeclient.CoreV1().Namespaces().Create(context.TODO(), tmpNs, metav1.CreateOptions{}) | ||
|
|
||
| defer func() { | ||
| kubeclient.CoreV1().Namespaces().Delete(context.TODO(), ns, metav1.DeleteOptions{}) | ||
| }() | ||
|
|
||
| g.By("create a deployment") | ||
| deploymentName := "hello-openshift" | ||
| containerName := "hello-openshift" | ||
| containerImage := "openshift/hello-openshift:invaid" | ||
| deployment := &appsv1.Deployment{ | ||
| ObjectMeta: metav1.ObjectMeta{ | ||
| Name: deploymentName, | ||
| }, | ||
| Spec: appsv1.DeploymentSpec{ | ||
| Replicas: ptr.To(int32(2)), // Number of desired replicas | ||
| Selector: &metav1.LabelSelector{ | ||
| MatchLabels: map[string]string{ | ||
| "app": containerName, | ||
| }, | ||
| }, | ||
| Template: corev1.PodTemplateSpec{ | ||
| ObjectMeta: metav1.ObjectMeta{ | ||
| Labels: map[string]string{ | ||
| "app": containerName, | ||
| }, | ||
| }, | ||
| Spec: corev1.PodSpec{ | ||
| Containers: []corev1.Container{ | ||
| { | ||
| Name: containerName, | ||
| Image: containerImage, | ||
| Ports: []corev1.ContainerPort{ | ||
| { | ||
| ContainerPort: 80, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| } | ||
| kubeclient.AppsV1().Deployments(ns).Create(context.TODO(), deployment, metav1.CreateOptions{}) | ||
|
|
||
| defer func() { | ||
| kubeclient.AppsV1().Deployments(ns).Delete(context.TODO(), deploymentName, metav1.DeleteOptions{}) | ||
| }() | ||
|
|
||
| err := wait.Poll(1*time.Minute, 3*time.Minute, func() (bool, error) { | ||
| allPods, err := kubeclient.CoreV1().Pods(ns).List(context.TODO(), metav1.ListOptions{}) | ||
| if err != nil { | ||
| log.Fatalf("Error listing pods: %v", err) | ||
| } | ||
| for _, pod := range allPods.Items { | ||
| if pod.Status.Phase == corev1.PodRunning { | ||
| return true, errors.New("there are pods running: " + pod.Name) | ||
| } | ||
| } | ||
| return true, nil | ||
| }) | ||
| allPods, _ := kubeclient.CoreV1().Pods(ns).List(context.TODO(), metav1.ListOptions{}) | ||
| fmt.Printf("there are %v pods\n", len(allPods.Items)) | ||
| for _, pod := range allPods.Items { | ||
| fmt.Printf(" - Pod: %s - %s\n", pod.Name, pod.Status.Phase) | ||
| } | ||
| o.Expect(kerrors.IsNotFound(err)).To(o.BeFalse(), "The NotFound error should not occur") | ||
|
|
||
| g.By("create a PodDisruptionBudget") | ||
| pdbName := "my-pdb" | ||
| pdb := &applyconfigurationspolicyv1.PodDisruptionBudgetApplyConfiguration{ | ||
| ObjectMetaApplyConfiguration: &clientmetav1.ObjectMetaApplyConfiguration{ | ||
| Name: &pdbName, | ||
| Namespace: &ns, | ||
| }, | ||
| Spec: &applyconfigurationspolicyv1.PodDisruptionBudgetSpecApplyConfiguration{ | ||
| MaxUnavailable: &intstr.IntOrString{ | ||
| Type: intstr.Int, | ||
| IntVal: 1, | ||
| }, | ||
| }, | ||
| } | ||
| kubeclient.PolicyV1().PodDisruptionBudgets(ns).Apply(context.TODO(), pdb, metav1.ApplyOptions{}) | ||
|
|
||
| defer func() { | ||
| kubeclient.PolicyV1().PodDisruptionBudgets(ns).Delete(context.TODO(), pdbName, metav1.DeleteOptions{}) | ||
| }() | ||
|
|
||
| g.By("wait some minutes, there is a critical issue for PDB") | ||
| token, _ := CreateServiceAccount(kubeclient, "monitorer", "cluster-admin", ns) | ||
| // TODO: get alert | ||
| fmt.Println(token) | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Precheck test has multiple issues and appears incomplete.
This test has several problems:
- Typo in image name – Line 154:
"openshift/hello-openshift:invaid"should be"invalid". - Confusing poll logic – Lines 194-211: The wait.Poll returns an error when a pod is running (line 201), then expects
IsNotFound(err)to be false (line 211). This logic is unclear and appears backwards. - Same List error handling issue – Line 211 uses
kerrors.IsNotFound(err)incorrectly (should checkerrdirectly). - Fatal error handling – Line 197:
log.Fatalfterminates the entire test run; use Gomega assertions instead:o.Expect(err).NotTo(o.HaveOccurred()). - Missing error checks – Lines 145, 188, 227: Resource creation operations don't check for errors.
- Incomplete test – Line 235: TODO comment indicates the test is unfinished (no alert fetching logic).
- Misleading title – The test is labeled "Precheck with oc adm upgrade recommend" but doesn't perform upgrade recommendations; it tests deployment and PDB behavior.
The test logic needs clarification. What is the intended behavior being tested here? If this is incomplete work for a future test case, consider removing it or marking it as g.Skip() until the implementation is complete.
🤖 Prompt for AI Agents
In test/cvo/cvo.go around lines 140-237: fix the image typo ("invaid" ->
"invalid"); replace all unchecked API calls (Namespaces().Create,
Deployments(ns).Create, Pods/List, PodDisruptionBudgets(ns).Apply and Delete
calls) to capture and assert errors with o.Expect(err).NotTo(o.HaveOccurred())
instead of ignoring them; remove log.Fatalf and use Gomega assertions
(o.Expect(err).NotTo(o.HaveOccurred())) for list errors; correct the wait.Poll
logic so it returns success when the expected condition holds (e.g., wait until
no pods are Running if that’s intended, or wait until pods are Running and
return (true, nil) accordingly) and assert the final err directly (do not use
kerrors.IsNotFound(err) incorrectly); implement or remove the TODO for alert
fetching (or mark the test with g.Skip() and update the test title to reflect
actual behavior) so the test is complete and its intent is clear.
This is the demo to show how we use client-go to automate a test case.
f9a032b to
338557b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (3)
test/cvo/cvo.go (3)
29-70: Fix multiple critical issues in CreateServiceAccount.This function has several problems that will cause runtime failures and logical errors:
- Lines 35, 69:
token.String()is invalid—TokenRequestdoesn't have aString()method. Usetoken.Status.Tokento access the token string.- Line 55: The
clusterRoleparameter is unused; the function always binds to"cluster-admin". Either use the parameter or remove it.- Line 50:
Namespacefield onClusterRoleBindingis invalid—ClusterRoleBindings are cluster-scoped resources and don't have a namespace.- Lines 45, 66: Using
o.Expect(which panics on failure) inside a function that returnserrorcreates inconsistent error handling.Apply this diff to fix these issues:
func CreateServiceAccount(client *kubernetes.Clientset, accountName string, clusterRole string, namespace string) (token string, err error) { _, err = client.CoreV1().ServiceAccounts(namespace).Get(context.TODO(), accountName, metav1.GetOptions{}) if err == nil { - token, err := client.CoreV1().ServiceAccounts(namespace).CreateToken(context.TODO(), accountName, &authenticationv1.TokenRequest{}, metav1.CreateOptions{}) - return token.String(), err + tokenReq, err := client.CoreV1().ServiceAccounts(namespace).CreateToken(context.TODO(), accountName, &authenticationv1.TokenRequest{}, metav1.CreateOptions{}) + if err != nil { + return "", err + } + return tokenReq.Status.Token, nil } account := &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Name: accountName, Namespace: namespace, }, } _, err = client.CoreV1().ServiceAccounts(namespace).Create(context.TODO(), account, metav1.CreateOptions{}) - o.Expect(err).NotTo(o.HaveOccurred()) + if err != nil { + return "", err + } rb := &rbacv1.ClusterRoleBinding{ ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("%s:%s:%s", namespace, clusterRole, accountName), - Namespace: namespace, }, RoleRef: rbacv1.RoleRef{ APIGroup: "rbac.authorization.k8s.io", Kind: "ClusterRole", - Name: "cluster-admin", + Name: clusterRole, }, Subjects: []rbacv1.Subject{ { Kind: "ServiceAccount", Name: accountName, Namespace: namespace, }, }, } _, err = client.RbacV1().ClusterRoleBindings().Create(context.TODO(), rb, metav1.CreateOptions{}) - o.Expect(err).NotTo(o.HaveOccurred()) + if err != nil { + return "", err + } - newToken, err := client.CoreV1().ServiceAccounts(namespace).CreateToken(context.TODO(), accountName, &authenticationv1.TokenRequest{}, metav1.CreateOptions{}) - return newToken.String(), err + tokenReq, err := client.CoreV1().ServiceAccounts(namespace).CreateToken(context.TODO(), accountName, &authenticationv1.TokenRequest{}, metav1.CreateOptions{}) + if err != nil { + return "", err + } + return tokenReq.Status.Token, nil }
104-105: Fix incorrect error handling on all List operations.All five List operations (lines 105, 115, 124, 133, 142) incorrectly use
kerrors.IsNotFound(err)to check for errors. This has two critical problems:
Silently masks real API failures: Any non-
NotFounderror (authentication, RBAC, network issues, etc.) makesIsNotFound(err)returnfalse, causing the expectation to pass even though the API call failed. The test then iterates over an empty/zero-valued list and can incorrectly report success.Wrong error type: Kubernetes List operations return an empty list with
err == nilwhen no items exist, not aNotFounderror. TheIsNotFoundcheck is designed for Get/Delete operations on named resources (single-resource operations), not collection endpoints.Apply this diff to fix all List error checks:
auths, err := client.Authentications().List(context.TODO(), metav1.ListOptions{}) - o.Expect(kerrors.IsNotFound(err)).To(o.BeFalse(), "The NotFound error should occur when listing authentications") + o.Expect(err).NotTo(o.HaveOccurred(), "failed to list authentications") g.By(fmt.Sprintf("checking if authentication with %s annotation exists", annotation)) for _, auth := range auths.Items { if _, ok := auth.Annotations[annotation]; ok { o.Expect(ok).NotTo(o.BeTrue(), fmt.Sprintf("Unexpectedly installed authentication %s which has '%s' annotation", auth.Name, annotation)) } } namespaces, err := kubeclient.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{}) - o.Expect(kerrors.IsNotFound(err)).To(o.BeFalse(), "The NotFound error should occur when listing namespaces") + o.Expect(err).NotTo(o.HaveOccurred(), "failed to list namespaces") g.By(fmt.Sprintf("checking if special resources with %s annotation exist in all namespaces", annotation)) for _, ns := range namespaces.Items { namespace := ns.Name fmt.Printf("namespace: %s\n", namespace) fmt.Println(" - Test services...") services, err := kubeclient.CoreV1().Services(namespace).List(context.TODO(), metav1.ListOptions{}) - o.Expect(kerrors.IsNotFound(err)).To(o.BeFalse(), "The NotFound error should occur when listing services") + o.Expect(err).NotTo(o.HaveOccurred(), "failed to list services") for _, service := range services.Items { if _, ok := service.Annotations[annotation]; ok { o.Expect(ok).NotTo(o.BeTrue(), fmt.Sprintf("Unexpectedly installed service %s which has '%s' annotation", service.Name, annotation)) } } fmt.Println(" - Test RoleBinding...") rolebindings, err := kubeclient.RbacV1().RoleBindings(namespace).List(context.TODO(), metav1.ListOptions{}) - o.Expect(kerrors.IsNotFound(err)).To(o.BeFalse(), "The NotFound error should occur when listing rolebindings") + o.Expect(err).NotTo(o.HaveOccurred(), "failed to list rolebindings") for _, rb := range rolebindings.Items { if _, ok := rb.Annotations[annotation]; ok { o.Expect(ok).NotTo(o.BeTrue(), fmt.Sprintf("Unexpectedly installed RoleBinding %s which has '%s' annotation", rb.Name, annotation)) } } fmt.Println(" - Test CronJob...") cronjobs, err := kubeclient.BatchV1().CronJobs(namespace).List(context.TODO(), metav1.ListOptions{}) - o.Expect(kerrors.IsNotFound(err)).To(o.BeFalse(), "The NotFound error should occur when listing cronjobs") + o.Expect(err).NotTo(o.HaveOccurred(), "failed to list cronjobs") for _, cj := range cronjobs.Items { if _, ok := cj.Annotations[annotation]; ok { o.Expect(ok).NotTo(o.BeTrue(), fmt.Sprintf("Unexpectedly installed CronJob %s which has %s annotation", cj.Name, annotation)) } }Also applies to: 114-115, 123-124, 132-133, 141-142
153-253: Fix multiple critical issues in precheck test.This test has several problems that affect correctness and completeness:
Line 167: Typo
"invaid"should be"invalid"(unless the invalid image is intentional for testing failure scenarios).Lines 158, 201, 240: Missing error checks on Create/Apply operations. These calls can fail silently, causing the test to proceed with invalid state.
Line 210:
log.Fatalfterminates the entire test process. Use Gomega assertions instead:o.Expect(err).NotTo(o.HaveOccurred()).Lines 207-218: The
wait.Polllogic is confusing—it returns an error when a pod is running (line 214), then expects the final error to not beNotFound(line 224). This appears backwards and uses the same incorrectIsNotFoundpattern on List operations.Line 224: Same List error handling issue—should check
errdirectly, not useIsNotFound.Line 251: TODO comment indicates incomplete implementation (no alert fetching logic).
Test title mismatch: The title mentions
"oc adm upgrade recommend"but the test doesn't perform upgrade recommendations; it tests deployment and PDB behavior.Apply this diff to fix the immediate correctness issues:
- containerImage := "openshift/hello-openshift:invaid" + containerImage := "openshift/hello-openshift:invalid" deployment := &appsv1.Deployment{ // ... deployment spec ... } - kubeclient.AppsV1().Deployments(ns).Create(context.TODO(), deployment, metav1.CreateOptions{}) + _, err := kubeclient.AppsV1().Deployments(ns).Create(context.TODO(), deployment, metav1.CreateOptions{}) + o.Expect(err).NotTo(o.HaveOccurred(), "failed to create deployment") defer func() { kubeclient.AppsV1().Deployments(ns).Delete(context.TODO(), deploymentName, metav1.DeleteOptions{}) }() - err := wait.Poll(1*time.Minute, 3*time.Minute, func() (bool, error) { + err = wait.Poll(1*time.Minute, 3*time.Minute, func() (bool, error) { allPods, err := kubeclient.CoreV1().Pods(ns).List(context.TODO(), metav1.ListOptions{}) if err != nil { - log.Fatalf("Error listing pods: %v", err) + return false, err } for _, pod := range allPods.Items { if pod.Status.Phase == corev1.PodRunning { - return true, errors.New("there are pods running: " + pod.Name) + return false, errors.New("there are pods running: " + pod.Name) } } return true, nil }) - allPods, _ := kubeclient.CoreV1().Pods(ns).List(context.TODO(), metav1.ListOptions{}) + allPods, err := kubeclient.CoreV1().Pods(ns).List(context.TODO(), metav1.ListOptions{}) + o.Expect(err).NotTo(o.HaveOccurred(), "failed to list pods after poll") fmt.Printf("there are %v pods\n", len(allPods.Items)) for _, pod := range allPods.Items { fmt.Printf(" - Pod: %s - %s\n", pod.Name, pod.Status.Phase) } - o.Expect(kerrors.IsNotFound(err)).To(o.BeFalse(), "The NotFound error should not occur") g.By("create a PodDisruptionBudget") pdbName := "my-pdb" pdb := &applyconfigurationspolicyv1.PodDisruptionBudgetApplyConfiguration{ // ... pdb spec ... } - kubeclient.PolicyV1().PodDisruptionBudgets(ns).Apply(context.TODO(), pdb, metav1.ApplyOptions{}) + _, err = kubeclient.PolicyV1().PodDisruptionBudgets(ns).Apply(context.TODO(), pdb, metav1.ApplyOptions{FieldManager: "test"}) + o.Expect(err).NotTo(o.HaveOccurred(), "failed to apply PDB")Regarding the incomplete test: The TODO at line 251 and missing alert logic suggest this test is still under development. Consider either completing the implementation or marking it with
g.Skip()until the alert fetching logic is ready.
🧹 Nitpick comments (1)
test/cvo/cvo.go (1)
3-27: Consider organizing imports by grouping local packages separately.Following Go conventions and the repository's coding guidelines, imports from this repository should be in their own section, separated from external dependencies.
Apply this diff to improve import organization:
import ( "context" "errors" "fmt" "log" "time" g "github.com/onsi/ginkgo/v2" o "github.com/onsi/gomega" appsv1 "k8s.io/api/apps/v1" authenticationv1 "k8s.io/api/authentication/v1" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" kerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/wait" clientmetav1 "k8s.io/client-go/applyconfigurations/meta/v1" applyconfigurationspolicyv1 "k8s.io/client-go/applyconfigurations/policy/v1" "k8s.io/client-go/kubernetes" "k8s.io/utils/ptr" - v1 "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1" + "github.com/openshift/cluster-version-operator/test/utilities" )Based on past review comments.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting
📒 Files selected for processing (1)
test/cvo/cvo.go(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**
⚙️ CodeRabbit configuration file
-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.
Files:
test/cvo/cvo.go
🧬 Code graph analysis (1)
test/cvo/cvo.go (1)
test/utilities/connection.go (2)
MustGetV1Client(65-71)MustGetKubeClient(56-62)
🔇 Additional comments (1)
test/cvo/cvo.go (1)
85-89: LGTM - sanity test serves its purpose.This simple test provides a useful signal for validating the test framework integration, as discussed in previous reviews.
| func DeleteServiceAccount(client *kubernetes.Clientset, accountName string, clusterRole string, namespace string) { | ||
| name := fmt.Sprintf("%s:%s:%s", namespace, clusterRole, accountName) | ||
| err := client.RbacV1().ClusterRoleBindings().Delete(context.TODO(), name, metav1.DeleteOptions{}) | ||
| if err != nil { | ||
| panic("failed to delete ClusterRoleBindings") | ||
| } | ||
|
|
||
| err = client.CoreV1().ServiceAccounts(namespace).Delete(context.TODO(), accountName, metav1.DeleteOptions{}) | ||
| if err != nil { | ||
| panic("failed to delete ServiceAccount") | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace panic calls with proper error handling or Gomega assertions.
Using panic for error handling in test helpers makes debugging more difficult and doesn't integrate well with Ginkgo's failure reporting. Consider either returning errors for the caller to handle or using Gomega assertions (o.Expect(err).NotTo(o.HaveOccurred())) for clearer test failure messages.
Apply this diff:
func DeleteServiceAccount(client *kubernetes.Clientset, accountName string, clusterRole string, namespace string) {
name := fmt.Sprintf("%s:%s:%s", namespace, clusterRole, accountName)
err := client.RbacV1().ClusterRoleBindings().Delete(context.TODO(), name, metav1.DeleteOptions{})
- if err != nil {
- panic("failed to delete ClusterRoleBindings")
- }
+ o.Expect(err).NotTo(o.HaveOccurred(), "failed to delete ClusterRoleBinding %s", name)
err = client.CoreV1().ServiceAccounts(namespace).Delete(context.TODO(), accountName, metav1.DeleteOptions{})
- if err != nil {
- panic("failed to delete ServiceAccount")
- }
+ o.Expect(err).NotTo(o.HaveOccurred(), "failed to delete ServiceAccount %s/%s", namespace, accountName)
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| func DeleteServiceAccount(client *kubernetes.Clientset, accountName string, clusterRole string, namespace string) { | |
| name := fmt.Sprintf("%s:%s:%s", namespace, clusterRole, accountName) | |
| err := client.RbacV1().ClusterRoleBindings().Delete(context.TODO(), name, metav1.DeleteOptions{}) | |
| if err != nil { | |
| panic("failed to delete ClusterRoleBindings") | |
| } | |
| err = client.CoreV1().ServiceAccounts(namespace).Delete(context.TODO(), accountName, metav1.DeleteOptions{}) | |
| if err != nil { | |
| panic("failed to delete ServiceAccount") | |
| } | |
| } | |
| func DeleteServiceAccount(client *kubernetes.Clientset, accountName string, clusterRole string, namespace string) { | |
| name := fmt.Sprintf("%s:%s:%s", namespace, clusterRole, accountName) | |
| err := client.RbacV1().ClusterRoleBindings().Delete(context.TODO(), name, metav1.DeleteOptions{}) | |
| o.Expect(err).NotTo(o.HaveOccurred(), "failed to delete ClusterRoleBinding %s", name) | |
| err = client.CoreV1().ServiceAccounts(namespace).Delete(context.TODO(), accountName, metav1.DeleteOptions{}) | |
| o.Expect(err).NotTo(o.HaveOccurred(), "failed to delete ServiceAccount %s/%s", namespace, accountName) | |
| } |
|
@JianLi-RH: The following tests failed, say
Full PR test history. Your PR dashboard. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here. |
In this PR, I finished 2 things:
/cc @wking @DavidHurta @PratikMahajan @hongkailiu @jhou1 @dis016 @jiajliu