Skip to content

OCPBUGS-100060: gate etcd member restarts on quorum and control plane node state - #1663

Open
mkowalski wants to merge 1 commit into
openshift:mainfrom
mkowalski:ocpbugs-100060-restart-member-precondition
Open

OCPBUGS-100060: gate etcd member restarts on quorum and control plane node state#1663
mkowalski wants to merge 1 commit into
openshift:mainfrom
mkowalski:ocpbugs-100060-restart-member-precondition

Conversation

@mkowalski

@mkowalski mkowalski commented Jul 29, 2026

Copy link
Copy Markdown

Summary

Second of two PRs for OCPBUGS-100060 (companion to openshift/library-go#2387): etcd quorum loss during upgrades when the revision installer restarts an etcd member while MCO is simultaneously rebooting another master.

Incident evidence (both runs: 2/3 members down → ~2min leaderless → cluster-wide API outage, aggregated apiservers returning 429 storage is (re)initializing):

Run installer kills member B master A goes down for reboot
2075907197388197888 13:52:21 (master-1) ~13:52:54 (master-0)
2077192709163978752 02:58:24 (master-1) ~02:58:50 (master-0)

The rebooting node keeps reporting Ready until it's actually down (in one run NotReady was only recorded after the reboot finished), and the cached member health (60s TTL) can be stale — so existing checks pass. The reliable early signal is the cordon that precedes the MCO drain by minutes.

Change:

  • ceohelpers.QuorumChecker gains IsSafeToRestartMember(ctx, targetNode): fresh (non-cached) member health must be quorum fault-tolerant, and no control-plane node other than the target may be cordoned or NotReady. Topology exemptions preserved (unsafe/SNO skips entirely; TNF keeps its pacemaker exception, consistent with CheckSafeToScaleCluster).
  • Wired via the new library-go WithInstallerPrecondition immediately before each installer pod (which restarts the member); when unmet the installer controller emits InstallerPreconditionNotMet and requeues (15s) — installs are only delayed, never aborted, resuming when the other master returns Ready.
  • Uses the non-cached etcd client for this check (the same staleness hazard already documented in starter.go for DualReplica).

⚠️ The vendored library-go change is included ad interim so this PR builds and can be payload-tested; it will be replaced by a proper go mod bump once openshift/library-go#2387 merges.

Test plan

  • gofmt, go vet, go build ./...
  • go test ./pkg/operator/ceohelpers/ — new TestQuorumCheck_IsSafeToRestartMember (all-healthy allows; other-node cordoned blocks; target-itself cordoned allows; other-node NotReady blocks; non-fault-tolerant quorum blocks); existing tests pass
  • payload-test metal-ipi upgrade jobs: verify no etcd leaderless windows (episodes previously 115-126s) and no 429 storage is (re)initializing bursts

This PR was generated using AI. Please verify before acting on it.

Summary by CodeRabbit

  • New Features

    • Added safety checks before restarting control plane members.
    • Restarts are now blocked when quorum is insufficient or other control plane nodes are cordoned or unhealthy.
    • Added handling for scaling configurations where restarts are considered safe by design.
  • Bug Fixes

    • Improved restart decisions by using current member health information, reducing the risk of stale status data.

The static pod installer restarts the etcd member on a node when rolling out
a new revision.  The quorum checks gate only revision creation, so an
installer pod could restart a member while another control plane node was
simultaneously down for a machine-config reboot: the rebooting node keeps
reporting Ready until it actually goes down, and the cached member health
(60s TTL) can also be stale.  With 2 of 3 members down the cluster is left
without an etcd leader for ~2 minutes and the whole API becomes unavailable
(OCPBUGS-100060).

Wire the new library-go installer precondition to a member restart safety
check: before creating an installer pod for a node, require that

  * fresh (non-cached) member health reports the cluster quorum fault
    tolerant, and
  * no control plane node other than the target is cordoned or not ready -
    the cordon that precedes an MCO drain/reboot is visible minutes before
    the node goes down, closing the race that member health alone cannot.

Existing topology exemptions are preserved: unsafe/single-node skips the
check entirely and Two Node with Fencing keeps its fault tolerance
exception, consistent with CheckSafeToScaleCluster.

The vendored library-go change (WithInstallerPrecondition) is included ad
interim and will be replaced by a proper bump once
openshift/library-go#2387 merges.

Assisted-By: Claude Fable 5
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Pipeline controller notification
This repo is configured to use the pipeline controller. Second-stage tests will be triggered either automatically or after lgtm label is added, depending on the repository configuration. The pipeline controller will automatically detect which contexts are required and will utilize /test Prow commands to trigger the second stage.

For optional jobs, comment /test ? to see a list of all defined jobs. To trigger manually all jobs from second stage use /pipeline required command.

This repository is configured in: LGTM mode

@openshift-ci-robot openshift-ci-robot added jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. labels Jul 29, 2026
@openshift-ci-robot

Copy link
Copy Markdown

@mkowalski: This pull request references Jira Issue OCPBUGS-100060, which is invalid:

  • expected the bug to target the "5.0.0" version, but no target version was set

Comment /jira refresh to re-evaluate validity if changes to the Jira bug are made, or edit the title of this pull request to link to a different bug.

The bug has been updated to refer to the pull request using the external bug tracker.

Details

In response to this:

Summary

Second of two PRs for OCPBUGS-100060 (companion to openshift/library-go#2387): etcd quorum loss during upgrades when the revision installer restarts an etcd member while MCO is simultaneously rebooting another master.

Incident evidence (both runs: 2/3 members down → ~2min leaderless → cluster-wide API outage, aggregated apiservers returning 429 storage is (re)initializing):

Run installer kills member B master A goes down for reboot
2075907197388197888 13:52:21 (master-1) ~13:52:54 (master-0)
2077192709163978752 02:58:24 (master-1) ~02:58:50 (master-0)

The rebooting node keeps reporting Ready until it's actually down (in one run NotReady was only recorded after the reboot finished), and the cached member health (60s TTL) can be stale — so existing checks pass. The reliable early signal is the cordon that precedes the MCO drain by minutes.

Change:

  • ceohelpers.QuorumChecker gains IsSafeToRestartMember(ctx, targetNode): fresh (non-cached) member health must be quorum fault-tolerant, and no control-plane node other than the target may be cordoned or NotReady. Topology exemptions preserved (unsafe/SNO skips entirely; TNF keeps its pacemaker exception, consistent with CheckSafeToScaleCluster).
  • Wired via the new library-go WithInstallerPrecondition immediately before each installer pod (which restarts the member); when unmet the installer controller emits InstallerPreconditionNotMet and requeues (15s) — installs are only delayed, never aborted, resuming when the other master returns Ready.
  • Uses the non-cached etcd client for this check (the same staleness hazard already documented in starter.go for DualReplica).

⚠️ The vendored library-go change is included ad interim so this PR builds and can be payload-tested; it will be replaced by a proper go mod bump once openshift/library-go#2387 merges.

Test plan

  • gofmt, go vet, go build ./...
  • go test ./pkg/operator/ceohelpers/ — new TestQuorumCheck_IsSafeToRestartMember (all-healthy allows; other-node cordoned blocks; target-itself cordoned allows; other-node NotReady blocks; non-fault-tolerant quorum blocks); existing tests pass
  • payload-test metal-ipi upgrade jobs: verify no etcd leaderless windows (episodes previously 115-126s) and no 429 storage is (re)initializing bursts

This PR was generated using AI. Please verify before acting on it.

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.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

The quorum checker gains per-node restart-safety evaluation using scaling strategy, etcd health, quorum tolerance, and control plane node status. Operator startup wires this check into static pod installation using a non-cached etcd client.

Changes

Member restart safety

Layer / File(s) Summary
Restart safety contract and quorum evaluation
pkg/operator/ceohelpers/quorum_check.go
Adds the restart-safety interface method, node lister dependency, and checks for scaling strategy, etcd fault tolerance, cordoning, and readiness.
Restart safety test coverage
pkg/operator/ceohelpers/quorum_check_test.go
Adds table-driven coverage for healthy, cordoned, unready, and insufficient-quorum scenarios and updates constructor wiring.
Installer precondition wiring
pkg/operator/starter.go
Constructs a restart checker with the non-cached etcd client and gates static pod installation on per-node restart safety.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant StaticPodInstaller
  participant QuorumCheck
  participant EtcdClient
  participant NodeLister
  StaticPodInstaller->>QuorumCheck: Check target node restart safety
  QuorumCheck->>EtcdClient: Evaluate member health and quorum tolerance
  QuorumCheck->>NodeLister: List control plane nodes
  QuorumCheck-->>StaticPodInstaller: Return safety decision and reason
Loading
🚥 Pre-merge checks | ✅ 15
✅ Passed checks (15 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: preventing etcd member restarts unless quorum and control plane node state are safe.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed The added test/subtest names are static literals; node names and other dynamic values appear only in test bodies, not titles.
Test Structure And Quality ✅ Passed These are plain table-driven unit tests, not Ginkgo; they add no cluster resources or waits, and follow existing repo test patterns.
Microshift Test Compatibility ✅ Passed No new Ginkgo e2e tests were added; the only new test is a plain Go unit test, so MicroShift API compatibility isn’t implicated.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No new Ginkgo e2e tests were added; the PR only adds Go unit tests and helper code.
Topology-Aware Scheduling Compatibility ✅ Passed No new pod scheduling constraints were introduced; the change adds a runtime restart precondition and preserves arbiter/two-node handling.
Ote Binary Stdout Contract ✅ Passed No new main/init/TestMain/setup stdout writes were added; touched code only adds quorum checks and tests, with no fmt.Print/Stdout usage in process-level paths.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed Only Go unit tests were added; no Ginkgo e2e constructs or IPv4/external-network assumptions were found in touched files.
No-Weak-Crypto ✅ Passed Touched files and patch scan show no MD5/SHA1/DES/RC4/3DES/Blowfish/ECB, custom crypto, or non-constant-time secret comparisons.
Container-Privileges ✅ Passed Touched files are Go logic only; no added privileged/securityContext fields or manifest changes were found in the PR diff.
No-Sensitive-Data-In-Logs ✅ Passed No new direct log statements expose secrets/PII; added messages are errors/events, not klog logs.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions
The command is terminated due to an error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions


Comment @coderabbitai help to get the list of available commands.

@openshift-ci
openshift-ci Bot requested review from jubittajohn and tjungblu July 29, 2026 13:37
@openshift-ci

openshift-ci Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign atiratree for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@mkowalski

Copy link
Copy Markdown
Author

/payload-aggregate periodic-ci-openshift-release-main-nightly-5.0-e2e-metal-ipi-upgrade-ovn-ipv6 10

@openshift-ci

openshift-ci Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

@mkowalski: trigger 1 job(s) for the /payload-(with-prs|job|aggregate|job-with-prs|aggregate-with-prs) command

  • periodic-ci-openshift-release-main-nightly-5.0-e2e-metal-ipi-upgrade-ovn-ipv6

See details on https://pr-payload-tests.ci.openshift.org/runs/ci/f6e49270-8b52-11f1-8a66-3fe54ab832c2-0

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/operator/ceohelpers/quorum_check.go`:
- Around line 61-102: Update IsSafeToRestartMember after nodeLister.List to
reject an empty node list instead of falling through to the safe result. Return
an unsafe result with a clear explanation that no control-plane nodes were
found, while preserving the existing error handling and per-node
cordon/readiness checks for non-empty lists.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 00ce89df-3d1e-4142-aa30-a77a5754ebe9

📥 Commits

Reviewing files that changed from the base of the PR and between 2d12f7a and 69b1571.

⛔ Files ignored due to path filters (2)
  • vendor/github.com/openshift/library-go/pkg/operator/staticpod/controller/installer/installer_controller.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/library-go/pkg/operator/staticpod/controllers.go is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (3)
  • pkg/operator/ceohelpers/quorum_check.go
  • pkg/operator/ceohelpers/quorum_check_test.go
  • pkg/operator/starter.go

Comment on lines +61 to +102
func (c *QuorumCheck) IsSafeToRestartMember(ctx context.Context, targetNodeName string) (bool, string, error) {
scalingStrategy, err := GetBootstrapScalingStrategy(c.operatorClient, c.namespaceLister, c.infraLister)
if err != nil {
return false, "", fmt.Errorf("IsSafeToRestartMember failed to get bootstrap scaling strategy: %w", err)
}
if scalingStrategy == UnsafeScalingStrategy {
return true, "", nil
}

// the cluster must currently tolerate the loss of one member
memberHealth, err := c.etcdClient.MemberHealth(ctx)
if err != nil {
return false, "", fmt.Errorf("IsSafeToRestartMember couldn't determine member health: %w", err)
}
// Two Node OpenShift with Fencing protects etcd via pacemaker; treat it as an exception to the fault
// tolerance rule, consistent with CheckSafeToScaleCluster.
if err := etcdcli.IsQuorumFaultTolerantErr(memberHealth); err != nil &&
!(len(memberHealth) == 2 && (scalingStrategy == TwoNodeScalingStrategy || scalingStrategy == DelayedTwoNodeScalingStrategy)) {
return false, err.Error(), nil
}

// no control plane node other than the target may be cordoned or not ready. Member health alone is not
// enough: a node that is about to reboot keeps reporting healthy until it actually goes down, while the
// cordon that precedes its drain is visible minutes in advance.
nodes, err := c.nodeLister.List(labels.Everything())
if err != nil {
return false, "", fmt.Errorf("IsSafeToRestartMember failed to list control plane nodes: %w", err)
}
for _, node := range nodes {
if node.Name == targetNodeName {
continue
}
if node.Spec.Unschedulable {
return false, fmt.Sprintf("control plane node %q is cordoned, likely about to be drained and rebooted; restarting the etcd member on %q now could lose quorum", node.Name, targetNodeName), nil
}
if !isNodeReady(node) {
return false, fmt.Sprintf("control plane node %q is not ready; restarting the etcd member on %q now could lose quorum", node.Name, targetNodeName), nil
}
}

return true, "", nil
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Empty node list silently treated as "safe" — fail-open gap.

If c.nodeLister.List(labels.Everything()) returns zero nodes (e.g., the control-plane node informer hasn't synced yet right after operator restart, or a lister/selector misconfiguration), the loop at Line 89 never executes and the function falls through to return true, "", nil at Line 101. That silently approves a restart with zero visibility into other control-plane nodes' state — precisely the failure mode (stale/missing state hiding an imminent reboot) this PR is meant to close for OCPBUGS-100060.

🛡️ Proposed fix: guard against an empty/unsynced node list
 	nodes, err := c.nodeLister.List(labels.Everything())
 	if err != nil {
 		return false, "", fmt.Errorf("IsSafeToRestartMember failed to list control plane nodes: %w", err)
 	}
+	if len(nodes) == 0 {
+		return false, "", fmt.Errorf("IsSafeToRestartMember found no control plane nodes; node lister may not be synced yet")
+	}
 	for _, node := range nodes {
📝 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.

Suggested change
func (c *QuorumCheck) IsSafeToRestartMember(ctx context.Context, targetNodeName string) (bool, string, error) {
scalingStrategy, err := GetBootstrapScalingStrategy(c.operatorClient, c.namespaceLister, c.infraLister)
if err != nil {
return false, "", fmt.Errorf("IsSafeToRestartMember failed to get bootstrap scaling strategy: %w", err)
}
if scalingStrategy == UnsafeScalingStrategy {
return true, "", nil
}
// the cluster must currently tolerate the loss of one member
memberHealth, err := c.etcdClient.MemberHealth(ctx)
if err != nil {
return false, "", fmt.Errorf("IsSafeToRestartMember couldn't determine member health: %w", err)
}
// Two Node OpenShift with Fencing protects etcd via pacemaker; treat it as an exception to the fault
// tolerance rule, consistent with CheckSafeToScaleCluster.
if err := etcdcli.IsQuorumFaultTolerantErr(memberHealth); err != nil &&
!(len(memberHealth) == 2 && (scalingStrategy == TwoNodeScalingStrategy || scalingStrategy == DelayedTwoNodeScalingStrategy)) {
return false, err.Error(), nil
}
// no control plane node other than the target may be cordoned or not ready. Member health alone is not
// enough: a node that is about to reboot keeps reporting healthy until it actually goes down, while the
// cordon that precedes its drain is visible minutes in advance.
nodes, err := c.nodeLister.List(labels.Everything())
if err != nil {
return false, "", fmt.Errorf("IsSafeToRestartMember failed to list control plane nodes: %w", err)
}
for _, node := range nodes {
if node.Name == targetNodeName {
continue
}
if node.Spec.Unschedulable {
return false, fmt.Sprintf("control plane node %q is cordoned, likely about to be drained and rebooted; restarting the etcd member on %q now could lose quorum", node.Name, targetNodeName), nil
}
if !isNodeReady(node) {
return false, fmt.Sprintf("control plane node %q is not ready; restarting the etcd member on %q now could lose quorum", node.Name, targetNodeName), nil
}
}
return true, "", nil
}
func (c *QuorumCheck) IsSafeToRestartMember(ctx context.Context, targetNodeName string) (bool, string, error) {
scalingStrategy, err := GetBootstrapScalingStrategy(c.operatorClient, c.namespaceLister, c.infraLister)
if err != nil {
return false, "", fmt.Errorf("IsSafeToRestartMember failed to get bootstrap scaling strategy: %w", err)
}
if scalingStrategy == UnsafeScalingStrategy {
return true, "", nil
}
// the cluster must currently tolerate the loss of one member
memberHealth, err := c.etcdClient.MemberHealth(ctx)
if err != nil {
return false, "", fmt.Errorf("IsSafeToRestartMember couldn't determine member health: %w", err)
}
// Two Node OpenShift with Fencing protects etcd via pacemaker; treat it as an exception to the fault
// tolerance rule, consistent with CheckSafeToScaleCluster.
if err := etcdcli.IsQuorumFaultTolerantErr(memberHealth); err != nil &&
!(len(memberHealth) == 2 && (scalingStrategy == TwoNodeScalingStrategy || scalingStrategy == DelayedTwoNodeScalingStrategy)) {
return false, err.Error(), nil
}
// no control plane node other than the target may be cordoned or not ready. Member health alone is not
// enough: a node that is about to reboot keeps reporting healthy until it actually goes down, while the
// cordon that precedes its drain is visible minutes in advance.
nodes, err := c.nodeLister.List(labels.Everything())
if err != nil {
return false, "", fmt.Errorf("IsSafeToRestartMember failed to list control plane nodes: %w", err)
}
if len(nodes) == 0 {
return false, "", fmt.Errorf("IsSafeToRestartMember found no control plane nodes; node lister may not be synced yet")
}
for _, node := range nodes {
if node.Name == targetNodeName {
continue
}
if node.Spec.Unschedulable {
return false, fmt.Sprintf("control plane node %q is cordoned, likely about to be drained and rebooted; restarting the etcd member on %q now could lose quorum", node.Name, targetNodeName), nil
}
if !isNodeReady(node) {
return false, fmt.Sprintf("control plane node %q is not ready; restarting the etcd member on %q now could lose quorum", node.Name, targetNodeName), nil
}
}
return true, "", nil
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/operator/ceohelpers/quorum_check.go` around lines 61 - 102, Update
IsSafeToRestartMember after nodeLister.List to reject an empty node list instead
of falling through to the safe result. Return an unsafe result with a clear
explanation that no control-plane nodes were found, while preserving the
existing error handling and per-node cordon/readiness checks for non-empty
lists.

@mkowalski

Copy link
Copy Markdown
Author

Payload aggregate results (10 runs, all rebooted 3/3 masters):

Metric Result
InstallerPreconditionNotMet events 5-6 per run — the guard actively fires during the risky windows
Upgrades completed / rollout deadlock 10/10 upgrades completed (upgrade junits 57/57 pass) — delays never stalled the rollout
429 storage is (re)initializing 0 events across all runs
Real etcd leaderless windows 0 (three runs showed lifecycle-interval gaps, all verified as data-coverage artifacts: kube-api disruption ~1s in those runs, impossible under real quorum loss)
Job results 6 SUCCESS, 4 FAILURE — all failures are post-upgrade conformance flakes (sig-network/sig-auth SecurityPenetration) or the known CVO-acknowledges-upgrade flake; none etcd-related

Baseline for context: ~8% of master-updating runs hit the quorum-loss race (expected ~0.8 occurrences in 10 runs), so the strongest evidence here is behavioral: the precondition demonstrably delays installer pods 5-6 times per upgrade exactly when another master is cordoned/rebooting, without ever blocking rollout progress.

Residual oauth-api disruption of 0-10s in these runs is the separate OCPBUGS-100065 mechanism (PRs #2730/#2732, not included in this payload).


This comment was generated using AI. Please verify before acting on it.

@openshift-ci

openshift-ci Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

@mkowalski: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/verify-deps 69b1571 link true /test verify-deps
ci/prow/configmap-scale 69b1571 link false /test configmap-scale

Full PR test history. Your PR dashboard.

Details

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants