Skip to content

Add the Lease Proxy Server implementation#4961

Merged
openshift-merge-bot[bot] merged 7 commits intoopenshift:mainfrom
danilo-gemoli:feat/ci-operator/lease-proxy-server
Feb 25, 2026
Merged

Add the Lease Proxy Server implementation#4961
openshift-merge-bot[bot] merged 7 commits intoopenshift:mainfrom
danilo-gemoli:feat/ci-operator/lease-proxy-server

Conversation

@danilo-gemoli
Copy link
Copy Markdown
Contributor

@danilo-gemoli danilo-gemoli commented Feb 23, 2026

#4958 introduced an HTTP server in ci-operator, while this PR adds some route to it:

/lease/acquire
/lease/release

implemented by pkg/lease/proxy/proxy.go.
The proxy server is quite dumb as it just relies on the lease client to forward the requests it gets from a multi-stage step. It does nothing more than that so far.

The stepLeaseProxyServer exposes the LEASE_PROXY_SERVER_URL environment variable that, in turns, is consumed by multiStageTestStep.
A multi-stage step pod uses $LEASE_PROXY_SERVER_URL to make calls like this:

$ curl "${LEASE_PROXY_SERVER_URL}/lease/acquire?type=aws-quota-slice"

Summary by CodeRabbit

  • New Features

    • Added an HTTP lease-proxy with acquire/release endpoints and a pluggable lease client.
    • Exposed lease-proxy URL via LEASE_PROXY_SERVER_URL and added HTTP server address to public configuration.
    • Lease client gains optional configuration for ID generation; fake client can be initialized with predefined resources.
  • Tests

    • Added unit tests for proxy endpoints, step validation/provides, environment exposure of the lease-proxy URL, and updated tests for the fake client constructor.

@openshift-ci openshift-ci bot requested review from Prucek and liangxia February 23, 2026 17:23
@openshift-ci openshift-ci bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Feb 23, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 23, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Tracks an HTTP server address into Config, exposes it as LEASE_PROXY_SERVER_URL, introduces a lease proxy HTTP component that forwards acquire/release requests to a pluggable lease client, and extends lease client/fake APIs (configurable randID and predefined resources); steps and tests updated to wire mux and address.

Changes

Cohort / File(s) Summary
HTTP server wiring
cmd/ci-operator/main.go, pkg/defaults/config.go
startHTTPServer now returns the listening address (string, error); run path uses a dedicated http.Server and mux; Config gains HTTPServerAddr and HTTPServerMux set from the new server.
API constants
pkg/api/constant.go
Added exported constant LeaseProxyServerURLEnvVarName = "LEASE_PROXY_SERVER_URL".
Lease proxy HTTP component
pkg/lease/proxy/proxy.go, pkg/lease/proxy/proxy_test.go
New proxy package: Proxy with RegisterHandlers; endpoints /lease/acquire and /lease/release; request parsing, error→status mapping, JSON acquire response; comprehensive handler tests.
Lease client options & fake client
pkg/lease/client.go, pkg/lease/fake.go
Added ClientOptions and WithRandID; NewClient accepts variadic opts. NewFakeClient signature extended to accept a resources map and store predefined resources; fake wired to use instance randID.
Step-level lease proxy integration
pkg/steps/lease_proxy.go, pkg/steps/lease_proxy_test.go, pkg/defaults/defaults.go, pkg/defaults/defaults_test.go
LeaseProxyStep now accepts srvAddr, srvMux, and leaseClient; step provides LEASE_PROXY_SERVER_URL, validates mux/address, and registers proxy handlers at runtime; defaults iterate returned steps and register provides; tests updated.
Environment propagation
pkg/steps/multi_stage/multi_stage.go, pkg/steps/multi_stage/multi_stage_test.go
Environment assembly now includes LEASE_PROXY_SERVER_URL from params; test added to assert exposure.
Test call-site updates
pkg/lease/client_test.go, pkg/steps/ip_pool_test.go, pkg/steps/lease_test.go
Updated NewFakeClient call sites to supply additional trailing argument(s) required by the extended fake client constructor.

Sequence Diagram

sequenceDiagram
    participant Client as Client
    participant Proxy as Lease Proxy Handler
    participant LeaseClient as Lease Client
    participant LeaseServer as Lease Backend

    Client->>Proxy: POST /lease/acquire?type=TYPE&count=N
    activate Proxy
    Proxy->>Proxy: validate params
    Proxy->>LeaseClient: Acquire(type, count)
    activate LeaseClient
    LeaseClient->>LeaseServer: Acquire request
    LeaseServer-->>LeaseClient: lease names
    deactivate LeaseClient
    Proxy-->>Client: 200 OK { "names": [...] }
    deactivate Proxy

    Client->>Proxy: POST /lease/release?name=NAME
    activate Proxy
    Proxy->>Proxy: validate params
    Proxy->>LeaseClient: Release(name)
    activate LeaseClient
    LeaseClient->>LeaseServer: Release request
    LeaseServer-->>LeaseClient: OK
    deactivate LeaseClient
    Proxy-->>Client: 204 No Content
    deactivate Proxy
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.35% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add the Lease Proxy Server implementation' directly and accurately describes the main change: introducing a new lease proxy HTTP server component with endpoints for acquiring and releasing leases.
Stable And Deterministic Test Names ✅ Passed All test names use stable, descriptive static identifiers with no dynamic values like timestamps, UUIDs, IPs, or pod names.
Test Structure And Quality ✅ Passed The new test files follow Go best practices with table-driven patterns, clear assertions, and no cluster dependencies.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/lease/proxy/proxy.go`:
- Around line 42-45: The validation error message incorrectly references
parameter "n"; update the error text to reference "count" instead: in the
strconv.ParseUint call that assigns c, err (the block using
strconv.ParseUint(count, 10, strconv.IntSize)), replace fmt.Errorf("parameter
\"n\" is not valid: %s", count) with an error message that names "count" (e.g.,
fmt.Errorf("parameter \"count\" is not valid: %s", count)) so callers see the
correct query parameter in proxy.go.
- Around line 106-120: The Content-Type header is being set after writing the
response body so it won't be sent; move w.Header().Set("Content-Type",
"application/json") to before the first write to the ResponseWriter (i.e.,
before the call that writes namesBytes via w.Write in the handler), ensuring the
header is set prior to sending the AcquireResponse JSON payload (refer to
AcquireResponse, namesBytes and the w.Write call); keep error handling paths
as-is but ensure any successful JSON response sets the header before writing.

In `@pkg/steps/lease_proxy.go`:
- Around line 49-59: The run() implementation on stepLeaseProxyServer
dereferences s.leaseClient and uses s.srvMux without nil checks which can panic;
add validation in the stepLeaseProxyServer.Validate() method to return a clear
error when s.leaseClient is nil or s.srvMux is nil (and optionally validate
s.logger), and update run() (the helper run(context.Context) and Run(ctx
context.Context) flow) to avoid dereferencing when those fields are nil (e.g.,
return an error from run if validation failed) so leaseproxy.New and
proxy.RegisterHandlers are only called when s.leaseClient and s.srvMux are
non-nil.

ℹ️ Review info

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

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between d9fe57e and cfd4e5a.

📒 Files selected for processing (15)
  • cmd/ci-operator/main.go
  • pkg/api/constant.go
  • pkg/defaults/config.go
  • pkg/defaults/defaults.go
  • pkg/defaults/defaults_test.go
  • pkg/lease/client_test.go
  • pkg/lease/fake.go
  • pkg/lease/proxy/proxy.go
  • pkg/lease/proxy/proxy_test.go
  • pkg/steps/ip_pool_test.go
  • pkg/steps/lease_proxy.go
  • pkg/steps/lease_proxy_test.go
  • pkg/steps/lease_test.go
  • pkg/steps/multi_stage/multi_stage.go
  • pkg/steps/multi_stage/multi_stage_test.go

Comment on lines 49 to +59
func (*stepLeaseProxyServer) Objects() []ctrlruntimeclient.Object { return nil }
func (*stepLeaseProxyServer) Validate() error { return nil }

func (s *stepLeaseProxyServer) Run(ctx context.Context) error {
return results.ForReason("executing_lease_proxy").ForError(s.run(ctx))
}

//nolint:unparam // Remove this as soon as this functions can return an error as well.
func (s *stepLeaseProxyServer) run(context.Context) error {
if 1 == 2 {
return fmt.Errorf("unreachable code to make the linter happy. Will be removed soon.")
}
s.logger.Info("TODO - Not implemented")
proxy := leaseproxy.New(s.logger, func() lease.Client { return *s.leaseClient })
proxy.RegisterHandlers(s.srvMux)
Copy link
Copy Markdown

@coderabbitai coderabbitai bot Feb 23, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add nil checks for leaseClient and srvMux to prevent panic.

run() dereferences s.leaseClient and uses s.srvMux without validation. A miswired config would panic at runtime. Consider validating these in Validate().

🛠️ Proposed fix
 import (
 	"context"
+	"errors"
 	"net/http"

 	"github.com/sirupsen/logrus"
@@
-func (*stepLeaseProxyServer) Validate() error                     { return nil }
+func (s *stepLeaseProxyServer) Validate() error {
+	if s.leaseClient == nil {
+		return errors.New("lease proxy server requires a lease client")
+	}
+	if s.srvMux == nil {
+		return errors.New("lease proxy server requires an HTTP server mux")
+	}
+	return nil
+}
📝 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 (*stepLeaseProxyServer) Objects() []ctrlruntimeclient.Object { return nil }
func (*stepLeaseProxyServer) Validate() error { return nil }
func (s *stepLeaseProxyServer) Run(ctx context.Context) error {
return results.ForReason("executing_lease_proxy").ForError(s.run(ctx))
}
//nolint:unparam // Remove this as soon as this functions can return an error as well.
func (s *stepLeaseProxyServer) run(context.Context) error {
if 1 == 2 {
return fmt.Errorf("unreachable code to make the linter happy. Will be removed soon.")
}
s.logger.Info("TODO - Not implemented")
proxy := leaseproxy.New(s.logger, func() lease.Client { return *s.leaseClient })
proxy.RegisterHandlers(s.srvMux)
func (*stepLeaseProxyServer) Objects() []ctrlruntimeclient.Object { return nil }
func (s *stepLeaseProxyServer) Validate() error {
if s.leaseClient == nil {
return errors.New("lease proxy server requires a lease client")
}
if s.srvMux == nil {
return errors.New("lease proxy server requires an HTTP server mux")
}
return nil
}
func (s *stepLeaseProxyServer) Run(ctx context.Context) error {
return results.ForReason("executing_lease_proxy").ForError(s.run(ctx))
}
//nolint:unparam // Remove this as soon as this functions can return an error as well.
func (s *stepLeaseProxyServer) run(context.Context) error {
proxy := leaseproxy.New(s.logger, func() lease.Client { return *s.leaseClient })
proxy.RegisterHandlers(s.srvMux)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/steps/lease_proxy.go` around lines 49 - 59, The run() implementation on
stepLeaseProxyServer dereferences s.leaseClient and uses s.srvMux without nil
checks which can panic; add validation in the stepLeaseProxyServer.Validate()
method to return a clear error when s.leaseClient is nil or s.srvMux is nil (and
optionally validate s.logger), and update run() (the helper run(context.Context)
and Run(ctx context.Context) flow) to avoid dereferencing when those fields are
nil (e.g., return an error from run if validation failed) so leaseproxy.New and
proxy.RegisterHandlers are only called when s.leaseClient and s.srvMux are
non-nil.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Nice catch for srvMux but the validation logic won't work for leaseClient. The lease client gets initialized after the validation procedure executes. If the initialization fails, the step isn't executed at all, therefore it should be quite safe to use it in this way.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@danilo-gemoli, thank you for the clarification! You're absolutely right—if leaseClient is initialized after validation and the step won't run on initialization failure, then the nil check for it isn't necessary.

I'll revise the suggestion to only validate srvMux:

🛠️ Revised suggestion
 import (
 	"context"
+	"errors"
 	"net/http"

 	"github.com/sirupsen/logrus"
@@
-func (*stepLeaseProxyServer) Validate() error                     { return nil }
+func (s *stepLeaseProxyServer) Validate() error {
+	if s.srvMux == nil {
+		return errors.New("lease proxy server requires an HTTP server mux")
+	}
+	return nil
+}

📝 Learnings were identified and not saved (knowledge base disabled). Enable

@danilo-gemoli
Copy link
Copy Markdown
Contributor Author

/test e2e

@danilo-gemoli
Copy link
Copy Markdown
Contributor Author

/retest-required

2 similar comments
@danilo-gemoli
Copy link
Copy Markdown
Contributor Author

/retest-required

@danilo-gemoli
Copy link
Copy Markdown
Contributor Author

/retest-required

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
pkg/lease/client.go (1)

49-51: Guard against a nil randID override.

A nil randID will panic at call sites. Keeping the default when nil makes the option safer.

♻️ Suggested tweak
 func WithRandID(randID func() string) ClientOptions {
-	return func(o *clientOptions) { o.randID = randID }
+	return func(o *clientOptions) {
+		if randID != nil {
+			o.randID = randID
+		}
+	}
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/lease/client.go` around lines 49 - 51, The WithRandID option should guard
against a nil randID to avoid panics; update the WithRandID function so it
checks if randID != nil before assigning to clientOptions.randID (i.e., only
override o.randID when the provided randID is non-nil), leaving the existing
default in clientOptions unchanged when nil is passed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/lease/fake.go`:
- Around line 47-60: The fake client currently discards any error returned by
addCall when a predefined resource is found; in AcquireWaitWithPriority and
Acquire return the found resource together with err instead of returning (res,
nil). Update the success branches in fakeClient.AcquireWaitWithPriority (lookup
key "acquireWaitWithPriority_%s_%s_%s_%s") and fakeClient.Acquire (lookup key
"acquire_%s_%s_%s") to return (res, err) so injected failures from addCall are
preserved.

In `@pkg/lease/proxy/proxy.go`:
- Around line 38-46: Parsed "count" currently allows zero; change the validation
so that after parsing (the strconv.ParseUint branch) you check that c > 0 and
return an error if c == 0 (e.g., fmt.Errorf("parameter \"count\" must be > 0:
%d", c)). Assign params.count only when c > 0; make the error surface as a
client/bad-request response (HTTP 400) so callers and Acquire (which expects
n>0) do not receive an empty-request.

In `@pkg/steps/lease_proxy.go`:
- Around line 52-57: The Validate method on stepLeaseProxyServer currently only
checks srvMux; also verify that the server address is set by checking s.srvAddr
(the field used to build LEASE_PROXY_SERVER_URL in Provides()) and return an
error if it's empty so downstream code doesn't get an empty
LEASE_PROXY_SERVER_URL; update stepLeaseProxyServer.Validate() to return a
descriptive error when s.srvAddr == "" (referencing Validate(),
stepLeaseProxyServer, srvAddr, and Provides()).

---

Nitpick comments:
In `@pkg/lease/client.go`:
- Around line 49-51: The WithRandID option should guard against a nil randID to
avoid panics; update the WithRandID function so it checks if randID != nil
before assigning to clientOptions.randID (i.e., only override o.randID when the
provided randID is non-nil), leaving the existing default in clientOptions
unchanged when nil is passed.

ℹ️ Review info

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

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between cfd4e5a and b019180.

📒 Files selected for processing (4)
  • pkg/lease/client.go
  • pkg/lease/fake.go
  • pkg/lease/proxy/proxy.go
  • pkg/steps/lease_proxy.go

Comment on lines 47 to 60
func (c *fakeClient) AcquireWaitWithPriority(ctx context.Context, rtype, state, dest, requestID string) (*common.Resource, error) {
err := c.addCall("acquireWaitWithPriority", rtype, state, dest, requestID)
if res, ok := c.resources[fmt.Sprintf("acquireWaitWithPriority_%s_%s_%s_%s", rtype, state, dest, requestID)]; ok {
return res, nil
}
return &common.Resource{Name: fmt.Sprintf("%s_%d", rtype, len(*c.calls)-1)}, err
}

func (c *fakeClient) Acquire(rtype, state, dest string) (*common.Resource, error) {
err := c.addCall("acquire", rtype, state, dest)
if res, ok := c.resources[fmt.Sprintf("acquire_%s_%s_%s", rtype, state, dest)]; ok {
return res, nil
}
return &common.Resource{Name: fmt.Sprintf("%s_%d", rtype, len(*c.calls)-1)}, err
Copy link
Copy Markdown

@coderabbitai coderabbitai bot Feb 24, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Preserve injected failures even when a predefined resource exists.

addCall can return an error, but the current branch returns nil when a resource is found, masking failures in tests. Return the resource with err instead.

🛠️ Suggested fix
 	if res, ok := c.resources[fmt.Sprintf("acquireWaitWithPriority_%s_%s_%s_%s", rtype, state, dest, requestID)]; ok {
-		return res, nil
+		return res, err
 	}
@@
 	if res, ok := c.resources[fmt.Sprintf("acquire_%s_%s_%s", rtype, state, dest)]; ok {
-		return res, nil
+		return res, err
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/lease/fake.go` around lines 47 - 60, The fake client currently discards
any error returned by addCall when a predefined resource is found; in
AcquireWaitWithPriority and Acquire return the found resource together with err
instead of returning (res, nil). Update the success branches in
fakeClient.AcquireWaitWithPriority (lookup key
"acquireWaitWithPriority_%s_%s_%s_%s") and fakeClient.Acquire (lookup key
"acquire_%s_%s_%s") to return (res, err) so injected failures from addCall are
preserved.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I don't want to address this issue in this PR

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@danilo-gemoli, understood! Would you like me to open a GitHub issue to track this for a future PR?

Comment on lines +38 to +46
count := r.URL.Query().Get("count")
if count == "" {
params.count = 1
} else {
c, err := strconv.ParseUint(count, 10, strconv.IntSize)
if err != nil {
return params, fmt.Errorf("parameter \"count\" is not valid: %s", count)
}
params.count = uint(c)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Reject count=0 to align with lease client expectations.

Acquire expects n > 0. Accepting count=0 returns an empty lease list, which is likely a caller error. Consider returning 400 instead.

🛠️ Suggested fix
 	} else {
 		c, err := strconv.ParseUint(count, 10, strconv.IntSize)
 		if err != nil {
 			return params, fmt.Errorf("parameter \"count\" is not valid: %s", count)
 		}
+		if c == 0 {
+			return params, errors.New("count must be greater than 0")
+		}
 		params.count = uint(c)
 	}
📝 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
count := r.URL.Query().Get("count")
if count == "" {
params.count = 1
} else {
c, err := strconv.ParseUint(count, 10, strconv.IntSize)
if err != nil {
return params, fmt.Errorf("parameter \"count\" is not valid: %s", count)
}
params.count = uint(c)
count := r.URL.Query().Get("count")
if count == "" {
params.count = 1
} else {
c, err := strconv.ParseUint(count, 10, strconv.IntSize)
if err != nil {
return params, fmt.Errorf("parameter \"count\" is not valid: %s", count)
}
if c == 0 {
return params, errors.New("count must be greater than 0")
}
params.count = uint(c)
}
🧰 Tools
🪛 golangci-lint (2.5.0)

[error] 41-41: : # github.com/openshift/ci-tools/pkg/api/testimagestreamtagimport/v1 [github.com/openshift/ci-tools/pkg/api/testimagestreamtagimport/v1.test]
pkg/api/testimagestreamtagimport/v1/register.go:41:3: cannot use &TestImageStreamTagImport{} (value of type *TestImageStreamTagImport) as "k8s.io/apimachinery/pkg/runtime".Object value in argument to scheme.AddKnownTypes: *TestImageStreamTagImport does not implement "k8s.io/apimachinery/pkg/runtime".Object (missing method DeepCopyObject)
pkg/api/testimagestreamtagimport/v1/register.go:42:3: cannot use &TestImageStreamTagImportList{} (value of type *TestImageStreamTagImportList) as "k8s.io/apimachinery/pkg/runtime".Object value in argument to scheme.AddKnownTypes: *TestImageStreamTagImportList does not implement "k8s.io/apimachinery/pkg/runtime".Object (missing method DeepCopyObject)

(typecheck)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/lease/proxy/proxy.go` around lines 38 - 46, Parsed "count" currently
allows zero; change the validation so that after parsing (the strconv.ParseUint
branch) you check that c > 0 and return an error if c == 0 (e.g.,
fmt.Errorf("parameter \"count\" must be > 0: %d", c)). Assign params.count only
when c > 0; make the error surface as a client/bad-request response (HTTP 400)
so callers and Acquire (which expects n>0) do not receive an empty-request.

@danilo-gemoli danilo-gemoli force-pushed the feat/ci-operator/lease-proxy-server branch from b019180 to 69a6390 Compare February 24, 2026 14:27
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/defaults/defaults.go (1)

1244-1255: ⚠️ Potential issue | 🟠 Major

Guard lease proxy step when HTTP server address/mux are missing.
isLeaseProxyServerAvailable only checks LeaseClientEnabled, so a missing HTTP server addr/mux can still create a lease proxy step that fails Validate(). Gate on the HTTP server inputs to avoid failing runs when the HTTP server isn’t configured.

🛠️ Suggested fix
func isLeaseProxyServerAvailable(cfg *Config) bool {
-	return cfg.LeaseClientEnabled
+	return cfg.LeaseClientEnabled && cfg.HTTPServerAddr != "" && cfg.HTTPServerMux != nil
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/defaults/defaults.go` around lines 1244 - 1255,
isLeaseProxyServerAvailable currently only checks cfg.LeaseClientEnabled which
allows leaseProxyServerStep to build a step even when HTTP inputs are missing;
update isLeaseProxyServerAvailable to also verify cfg.HTTPServerAddr is
non-empty and cfg.HTTPServerMux is non-nil (and optionally cfg.LeaseClient is
non-nil) so leaseProxyServerStep returns an empty slice when any required HTTP
server input is missing, preventing a step that would fail Validate(); adjust
references in leaseProxyServerStep to rely on the updated
isLeaseProxyServerAvailable guard.
♻️ Duplicate comments (2)
pkg/lease/fake.go (1)

47-51: ⚠️ Potential issue | 🟡 Minor

Return injected errors alongside predefined resources.
addCall can inject failures; returning (res, nil) masks them and makes tests unable to assert error paths.

🛠️ Suggested fix
	if res, ok := c.resources[fmt.Sprintf("acquireWaitWithPriority_%s_%s_%s_%s", rtype, state, dest, requestID)]; ok {
-		return res, nil
+		return res, err
 	}
@@
	if res, ok := c.resources[fmt.Sprintf("acquire_%s_%s_%s", rtype, state, dest)]; ok {
-		return res, nil
+		return res, err
 	}

Also applies to: 56-59

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/lease/fake.go` around lines 47 - 51, The test double masks injected
errors from addCall: in fakeClient.AcquireWaitWithPriority (and the analogous
method around lines 56-59) you should check the error returned by c.addCall(...)
and, if non-nil, return that error instead of returning (res, nil); locate the
calls to addCall in the methods named AcquireWaitWithPriority (and the other
fakeClient method using the resources map) and change the control flow to return
(nil, err) when addCall returns an error, otherwise proceed to look up and
return the resource from c.resources as before.
pkg/lease/proxy/proxy.go (1)

38-89: ⚠️ Potential issue | 🟡 Minor

Reject count=0 instead of returning an empty lease list.
Acquire expects n > 0; returning 200 for count=0 hides caller errors.

🛠️ Suggested fix
	c, err := strconv.ParseUint(count, 10, strconv.IntSize)
	if err != nil {
		return params, fmt.Errorf("parameter \"count\" is not valid: %s", count)
	}
+	if c == 0 {
+		return params, errors.New("count must be greater than 0")
+	}
	params.count = uint(c)
-	if params.count == 0 {
-		p.writeAcquireResponse(w, []string{})
-		return
-	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/lease/proxy/proxy.go` around lines 38 - 89, The handler Proxy.acquire
currently accepts count==0 and returns an empty lease list; instead, detect when
params.count == 0 after parseAcquireParams and respond with a 400 Bad Request
(log via p.logger.WithField/WithError or Warnf) and an explanatory error message
(e.g. "count must be > 0") rather than calling p.writeAcquireResponse; update
the logic in Proxy.acquire to reject zero counts and return immediately so
callers receive an error instead of a 200 with an empty list.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@pkg/defaults/defaults.go`:
- Around line 1244-1255: isLeaseProxyServerAvailable currently only checks
cfg.LeaseClientEnabled which allows leaseProxyServerStep to build a step even
when HTTP inputs are missing; update isLeaseProxyServerAvailable to also verify
cfg.HTTPServerAddr is non-empty and cfg.HTTPServerMux is non-nil (and optionally
cfg.LeaseClient is non-nil) so leaseProxyServerStep returns an empty slice when
any required HTTP server input is missing, preventing a step that would fail
Validate(); adjust references in leaseProxyServerStep to rely on the updated
isLeaseProxyServerAvailable guard.

---

Duplicate comments:
In `@pkg/lease/fake.go`:
- Around line 47-51: The test double masks injected errors from addCall: in
fakeClient.AcquireWaitWithPriority (and the analogous method around lines 56-59)
you should check the error returned by c.addCall(...) and, if non-nil, return
that error instead of returning (res, nil); locate the calls to addCall in the
methods named AcquireWaitWithPriority (and the other fakeClient method using the
resources map) and change the control flow to return (nil, err) when addCall
returns an error, otherwise proceed to look up and return the resource from
c.resources as before.

In `@pkg/lease/proxy/proxy.go`:
- Around line 38-89: The handler Proxy.acquire currently accepts count==0 and
returns an empty lease list; instead, detect when params.count == 0 after
parseAcquireParams and respond with a 400 Bad Request (log via
p.logger.WithField/WithError or Warnf) and an explanatory error message (e.g.
"count must be > 0") rather than calling p.writeAcquireResponse; update the
logic in Proxy.acquire to reject zero counts and return immediately so callers
receive an error instead of a 200 with an empty list.

ℹ️ Review info

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

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between b019180 and 69a6390.

📒 Files selected for processing (16)
  • cmd/ci-operator/main.go
  • pkg/api/constant.go
  • pkg/defaults/config.go
  • pkg/defaults/defaults.go
  • pkg/defaults/defaults_test.go
  • pkg/lease/client.go
  • pkg/lease/client_test.go
  • pkg/lease/fake.go
  • pkg/lease/proxy/proxy.go
  • pkg/lease/proxy/proxy_test.go
  • pkg/steps/ip_pool_test.go
  • pkg/steps/lease_proxy.go
  • pkg/steps/lease_proxy_test.go
  • pkg/steps/lease_test.go
  • pkg/steps/multi_stage/multi_stage.go
  • pkg/steps/multi_stage/multi_stage_test.go
🚧 Files skipped from review as they are similar to previous changes (7)
  • pkg/steps/ip_pool_test.go
  • pkg/defaults/config.go
  • pkg/api/constant.go
  • pkg/steps/multi_stage/multi_stage_test.go
  • pkg/steps/multi_stage/multi_stage.go
  • pkg/steps/lease_test.go
  • pkg/lease/client_test.go

@danilo-gemoli
Copy link
Copy Markdown
Contributor Author

/test e2e

@danilo-gemoli
Copy link
Copy Markdown
Contributor Author

/test e2e

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a 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

🧹 Nitpick comments (1)
pkg/defaults/defaults.go (1)

124-127: Loop variable leaseProxyServerStep shadows the function of the same name.

The iteration variable and the function it ranges over share the identical identifier. While Go evaluates the range expression before entering the loop body so there is no runtime ambiguity here, this name collision makes the code harder to scan and is a trap for future refactors.

♻️ Proposed rename of loop variable
-	for _, leaseProxyServerStep := range leaseProxyServerStep(cfg) {
-		buildSteps = append(buildSteps, leaseProxyServerStep)
-		addProvidesForStep(leaseProxyServerStep, cfg.params)
+	for _, lps := range leaseProxyServerStep(cfg) {
+		buildSteps = append(buildSteps, lps)
+		addProvidesForStep(lps, cfg.params)
	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/defaults/defaults.go` around lines 124 - 127, The loop variable
leaseProxyServerStep shadows the function leaseProxyServerStep; rename the
iteration variable (e.g., to step or leaseProxyStep) in the for-range to avoid
the name collision and update its usages inside the loop (buildSteps =
append(buildSteps, <newName>) and addProvidesForStep(<newName>, cfg.params)) so
the code references the new loop variable while leaving the leaseProxyServerStep
function unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/defaults/defaults.go`:
- Around line 1244-1246: Update the guard in isLeaseProxyServerAvailable to also
verify cfg.LeaseClient != nil; currently it only checks cfg.LeaseClientEnabled,
cfg.HTTPServerAddr, and cfg.HTTPServerMux, so add the nil-check to avoid a
potential panic in stepLeaseProxyServer.run() when the anonymous function
dereferences LeaseClient—modify the function isLeaseProxyServerAvailable to
return cfg.LeaseClientEnabled && cfg.LeaseClient != nil && cfg.HTTPServerAddr !=
"" && cfg.HTTPServerMux != nil.

---

Nitpick comments:
In `@pkg/defaults/defaults.go`:
- Around line 124-127: The loop variable leaseProxyServerStep shadows the
function leaseProxyServerStep; rename the iteration variable (e.g., to step or
leaseProxyStep) in the for-range to avoid the name collision and update its
usages inside the loop (buildSteps = append(buildSteps, <newName>) and
addProvidesForStep(<newName>, cfg.params)) so the code references the new loop
variable while leaving the leaseProxyServerStep function unchanged.

ℹ️ Review info

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

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 69a6390 and e9347de.

📒 Files selected for processing (1)
  • pkg/defaults/defaults.go

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Feb 25, 2026
@danilo-gemoli
Copy link
Copy Markdown
Contributor Author

/label tide/merge-method-squash

@openshift-ci openshift-ci bot added the tide/merge-method-squash Denotes a PR that should be squashed by tide when it merges. label Feb 25, 2026
@danilo-gemoli
Copy link
Copy Markdown
Contributor Author

/test e2e

@openshift-ci openshift-ci bot removed the lgtm Indicates that a PR is ready to be merged. label Feb 25, 2026
@danilo-gemoli
Copy link
Copy Markdown
Contributor Author

/test e2e

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
pkg/defaults/defaults_test.go (1)

1866-1868: Use the API constant for the env var key to avoid drift.

At Line 1867, prefer api.LeaseProxyServerURLEnvVarName instead of the raw "LEASE_PROXY_SERVER_URL" string so this test stays aligned with the public constant.

♻️ Proposed change
 		expectedParams: map[string]string{
-			"LEASE_PROXY_SERVER_URL": "http://10.0.0.1:8080",
+			api.LeaseProxyServerURLEnvVarName: "http://10.0.0.1:8080",
 		},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/defaults/defaults_test.go` around lines 1866 - 1868, Replace the
hard-coded env var key in the test's expectedParams map with the public API
constant to avoid drift: change the map key currently using the literal
"LEASE_PROXY_SERVER_URL" to use api.LeaseProxyServerURLEnvVarName (the test
referencing expectedParams in defaults_test.go) so the test stays aligned with
the constant.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@pkg/defaults/defaults_test.go`:
- Around line 1866-1868: Replace the hard-coded env var key in the test's
expectedParams map with the public API constant to avoid drift: change the map
key currently using the literal "LEASE_PROXY_SERVER_URL" to use
api.LeaseProxyServerURLEnvVarName (the test referencing expectedParams in
defaults_test.go) so the test stays aligned with the constant.

ℹ️ Review info

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

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between e9347de and be7b976.

📒 Files selected for processing (1)
  • pkg/defaults/defaults_test.go

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Feb 25, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci bot commented Feb 25, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: danilo-gemoli, Prucek

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

The pull request process is described here

Details Needs approval from an approver in each of these files:
  • OWNERS [Prucek,danilo-gemoli]

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

@danilo-gemoli
Copy link
Copy Markdown
Contributor Author

/test images

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci bot commented Feb 25, 2026

@danilo-gemoli: The following test 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/breaking-changes be7b976 link false /test breaking-changes

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.

@openshift-merge-bot openshift-merge-bot bot merged commit 9baa38a into openshift:main Feb 25, 2026
13 of 14 checks passed
@danilo-gemoli danilo-gemoli deleted the feat/ci-operator/lease-proxy-server branch March 4, 2026 08:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged. tide/merge-method-squash Denotes a PR that should be squashed by tide when it merges.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants