Skip to content

OCPBUGS-86886: modernize dependency of k8s imports#92

Open
rikatz wants to merge 5 commits into
openshift:mainfrom
rikatz:remove-k8s-import
Open

OCPBUGS-86886: modernize dependency of k8s imports#92
rikatz wants to merge 5 commits into
openshift:mainfrom
rikatz:remove-k8s-import

Conversation

@rikatz
Copy link
Copy Markdown
Member

@rikatz rikatz commented Jun 2, 2026

This PR removes dependency of imports that were once necessary but were moved to a proper package, reducing the surface of import of libraries on route-controller-manager

Summary by CodeRabbit

  • New Features
    • Added an in-memory CIDR-backed IP range allocator with allocate/release/next/has operations.
  • Documentation
    • Added README documenting the IP allocator behavior and constraints.
  • Tests
    • Added unit tests covering allocator behavior, errors, and edge cases.
  • Chores
    • Removed several unused dependencies.
  • Refactor
    • Updated internal Kubernetes client/controller integration to modern scheme/queue handling.

@openshift-ci-robot openshift-ci-robot added jira/severity-low Referenced Jira bug's severity is low for the branch this PR is targeting. 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 Jun 2, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

@rikatz: This pull request references Jira Issue OCPBUGS-86886, 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:

This PR removes dependency of imports that were once necessary but were moved to a proper package, reducing the surface of import of libraries on route-controller-manager

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.

@rikatz
Copy link
Copy Markdown
Member Author

rikatz commented Jun 2, 2026

/jira refresh

@openshift-ci-robot openshift-ci-robot added jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. and removed jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. labels Jun 2, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

@rikatz: This pull request references Jira Issue OCPBUGS-86886, which is valid. The bug has been moved to the POST state.

3 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (5.0.0) matches configured target version for branch (5.0.0)
  • bug is in the state New, which is one of the valid states (NEW, ASSIGNED, POST)
Details

In response to this:

/jira refresh

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
Copy link
Copy Markdown

coderabbitai Bot commented Jun 2, 2026

Walkthrough

Removes legacy k8s and container-image indirect deps from go.mod, migrates ingress controllers to client-go scheme, replaces controller.KeyFunc usage with cache.DeletionHandlingMetaNamespaceKeyFunc in ingressip controller, and adds a new in-memory CIDR-backed IP allocator with README and tests.

Changes

Legacy Kubernetes API cleanup and modern scheme migration

Layer / File(s) Summary
Indirect dependency removal
go.mod
Removed k8s.io/kubernetes and five unused indirect dependencies: github.com/distribution/reference, github.com/opencontainers/go-digest, github.com/robfig/cron/v3, k8s.io/component-helpers, and k8s.io/kubelet.
Legacy scheme to client-go scheme migration
pkg/route/ingress/ingress.go, pkg/route/ingressip/service_ingressip_controller.go
Switched event recorder initialization to use k8s.io/client-go/kubernetes/scheme (scheme.Scheme) and removed legacy legacyscheme imports.
Worker queue key generation refactoring
pkg/route/ingressip/service_ingressip_controller.go
Replaced controller.KeyFunc with cache.DeletionHandlingMetaNamespaceKeyFunc at enqueue, re-adding pending services after sync, and when clearing old allocations.
Test infrastructure updates
pkg/route/ingressip/service_ingressip_controller_test.go
Removed deprecated k8s.io/kubernetes/pkg/controller import and changed shared informer factory resync period to 0 in tests.
IP allocator README and core implementation
pkg/utils/ipallocator/README.md, pkg/utils/ipallocator/allocator.go
Added README and bitmap-backed allocation strategy with mutex, randomized scan strategy, and allocation helpers.
IP allocator public API and helpers
pkg/utils/ipallocator/ipallocator.go
Added exported Range type, errors (ErrFull, ErrAllocated, ErrNotInRange), NewInMemory constructor, and methods: Free, Allocate, AllocateNext, Release, Has, plus offset calculation helpers.
IP allocator unit tests
pkg/utils/ipallocator/ipallocator_test.go
Comprehensive tests for constructor, allocation/release semantics, error cases, exhaustion, and full allocate/release cycle.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 14 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (14 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main objective: modernizing Kubernetes imports by removing dependencies on legacy k8s.io/kubernetes components and switching to current client-go standards.
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 All test functions use stable, static names without dynamic data. Standard Go testing with table-driven tests; descriptions are static strings only in assertions.
Test Structure And Quality ✅ Passed The PR contains no Ginkgo tests. Test files use Go's standard testing package (testing.T); check is not applicable to this codebase.
Microshift Test Compatibility ✅ Passed No Ginkgo e2e tests are added in this PR. The new ipallocator_test.go file contains standard Go unit tests using testing.T, not Ginkgo framework. The check is not applicable.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No Ginkgo e2e tests are added in this PR. All test code uses standard Go testing.T framework (unit tests), so SNO compatibility check is not applicable.
Topology-Aware Scheduling Compatibility ✅ Passed PR refactors imports and removes k8s.io/kubernetes dependency. No deployment manifests or scheduling constraints (affinity, nodeSelector, topology spread, PDB) are added or modified.
Ote Binary Stdout Contract ✅ Passed No process-level stdout writes detected. New ipallocator package only uses fmt.Sprintf/Errorf (safe), controller changes have no stdout, and tests are standard Go (no TestMain/suite setup).
Ipv6 And Disconnected Network Test Compatibility ✅ Passed No Ginkgo e2e tests are added in this PR; the test files are standard Go unit tests using the testing package, not Ginkgo.
No-Weak-Crypto ✅ Passed No weak cryptography detected. PR adds IP allocator (bitmap-based, not crypto), updates schemes, removes k8s.io/kubernetes dependency. No MD5/SHA1/DES/RC4, custom crypto, or unsafe secret comparisons.
Container-Privileges ✅ Passed This PR contains only Go code and dependency changes with no container/K8s manifests or container security configurations, making the container-privileges check not applicable.
No-Sensitive-Data-In-Logs ✅ Passed No sensitive data (passwords, tokens, API keys, PII, session IDs) exposed in logs; only operational data (IP addresses, service identifiers) logged at debug/verbose levels.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@openshift-ci openshift-ci Bot requested review from alebedev87 and knobunc June 2, 2026 16:19
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Jun 2, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: rikatz

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:

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

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jun 2, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

@rikatz: This pull request references Jira Issue OCPBUGS-86886, which is valid.

3 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (5.0.0) matches configured target version for branch (5.0.0)
  • bug is in the state POST, which is one of the valid states (NEW, ASSIGNED, POST)
Details

In response to this:

This PR removes dependency of imports that were once necessary but were moved to a proper package, reducing the surface of import of libraries on route-controller-manager

Summary by CodeRabbit

  • Chores
  • Updated dependencies by removing unused indirect packages.
  • Refactored internal Kubernetes client integration to use current standards instead of legacy components.

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.

@rikatz rikatz force-pushed the remove-k8s-import branch from ffc2f5b to 31a2af8 Compare June 2, 2026 16:48
@bentito
Copy link
Copy Markdown

bentito commented Jun 2, 2026

I think this PR takes care of everything in pkg/route/ingress/ but we still leave a dependency in pkg/route/ingressip/
We could ignore that as k8s.io/kubernetes/pkg/registry/core/service/ipallocator has not been lifted out into place truly meant for external use. But then we keep the dependency on k8s.io/kubernetes from a scanner perspective.

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: 2

🤖 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/utils/ipallocator/ipallocator_test.go`:
- Line 45: Replace the ignored error returns from NewInMemory(...) and
r.Allocate(...) in the ipallocator tests so failures surface immediately: after
calling NewInMemory(...) (symbol NewInMemory) check the returned error and fail
the test (e.g., t.Fatalf or require.NoError) instead of using “_”, and likewise
check the error returned by Allocate (symbol Allocate) and fail the test on
error; apply this change to every test that currently discards those errors so
setup/allocation errors break the test immediately.

In `@pkg/utils/ipallocator/ipallocator.go`:
- Around line 168-184: The contains() logic currently truncates the big.Int
delta to int64/int via calculateIPOffset, which can overflow for large IPv6
ranges; change calculateIPOffset to return the full *big.Int delta
(netutils.BigForIP(ip).Sub(base)) and update Range.contains to compare that
big.Int directly: check delta.Sign() < 0 or
delta.Cmp(big.NewInt(0).SetInt64(int64(r.max))) >= 0 to decide out-of-range, and
only after those checks convert the delta to a Go int (ensuring it fits, e.g.
via delta.IsInt64() and bounds against runtime.MaxInt) before returning the
offset; update references to calculateIPOffset and the return types accordingly
to avoid any Int64()/int truncation.
🪄 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: ce8607bd-6377-4d23-bd20-e8cdebaba694

📥 Commits

Reviewing files that changed from the base of the PR and between ffc2f5b and d4a98a4.

⛔ Files ignored due to path filters (140)
  • go.sum is excluded by !**/*.sum
  • vendor/github.com/distribution/reference/.gitattributes is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/.gitignore is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/.golangci.yml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/CODE-OF-CONDUCT.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/CONTRIBUTING.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/GOVERNANCE.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/MAINTAINERS is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/Makefile is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/SECURITY.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/distribution-logo.svg is excluded by !**/*.svg, !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/helpers.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/normalize.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/reference.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/regexp.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/distribution/reference/sort.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/opencontainers/go-digest/.mailmap is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/opencontainers/go-digest/.pullapprove.yml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/opencontainers/go-digest/.travis.yml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/opencontainers/go-digest/CONTRIBUTING.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/opencontainers/go-digest/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/opencontainers/go-digest/LICENSE.docs is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/opencontainers/go-digest/MAINTAINERS is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/opencontainers/go-digest/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/opencontainers/go-digest/algorithm.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/opencontainers/go-digest/digest.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/opencontainers/go-digest/digester.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/opencontainers/go-digest/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/opencontainers/go-digest/verifiers.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/robfig/cron/v3/.gitignore is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/robfig/cron/v3/.travis.yml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/robfig/cron/v3/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/robfig/cron/v3/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/robfig/cron/v3/chain.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/robfig/cron/v3/constantdelay.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/robfig/cron/v3/cron.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/robfig/cron/v3/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/robfig/cron/v3/logger.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/robfig/cron/v3/option.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/robfig/cron/v3/parser.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/robfig/cron/v3/spec.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/apiextensions-apiserver/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/apiextensions-apiserver/pkg/features/OWNERS is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/apiextensions-apiserver/pkg/features/kube_features.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/client-go/util/retry/OWNERS is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/client-go/util/retry/util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/component-helpers/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/component-helpers/node/util/sysctl/namespace.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/component-helpers/node/util/sysctl/sysctl.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/component-helpers/resource/OWNERS is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/component-helpers/resource/helpers.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/component-helpers/scheduling/corev1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/component-helpers/scheduling/corev1/helpers.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/component-helpers/scheduling/corev1/nodeaffinity/nodeaffinity.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/controller-manager/pkg/features/OWNERS is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/controller-manager/pkg/features/kube_features.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubelet/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubelet/pkg/apis/OWNERS is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubelet/pkg/apis/well_known_labels.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/api/legacyscheme/scheme.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/api/service/OWNERS is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/api/service/util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/api/service/warnings.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/api/servicecidr/servicecidr.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/api/v1/pod/util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/api/v1/service/util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/apps/OWNERS is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/apps/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/apps/register.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/apps/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/apps/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/kubernetes/pkg/apis/autoscaling/OWNERS is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/autoscaling/annotations.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/autoscaling/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/autoscaling/helpers.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/autoscaling/register.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/autoscaling/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/autoscaling/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/kubernetes/pkg/apis/certificates/OWNERS is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/certificates/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/certificates/helpers.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/certificates/register.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/certificates/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/certificates/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/kubernetes/pkg/apis/core/OWNERS is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/core/annotation_key_constants.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/core/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/core/helper/helpers.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/core/helper/qos/qos.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/core/install/OWNERS is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/core/install/install.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/core/json.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/core/objectreference.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/core/pods/helpers.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/core/register.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/core/resource.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/core/taint.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/core/toleration.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/core/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/core/v1/OWNERS is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/core/v1/conversion.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/core/v1/defaults.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/core/v1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/core/v1/helper/helpers.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/core/v1/register.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/core/v1/zz_generated.conversion.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/kubernetes/pkg/apis/core/v1/zz_generated.defaults.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/kubernetes/pkg/apis/core/v1/zz_generated.validations.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/kubernetes/pkg/apis/core/validation/OWNERS is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/core/validation/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/core/validation/events.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/core/validation/names.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/core/validation/validation.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/apis/core/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/kubernetes/pkg/capabilities/capabilities.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/capabilities/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/controller/OWNERS is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/controller/controller_ref_manager.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/controller/controller_utils.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/controller/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/features/OWNERS is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/features/client_adapter.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/features/kube_features.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/fieldpath/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/fieldpath/fieldpath.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/registry/core/service/allocator/bitmap.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/registry/core/service/allocator/interfaces.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/registry/core/service/allocator/utils.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/registry/core/service/ipallocator/bitmap.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/registry/core/service/ipallocator/cidrallocator.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/registry/core/service/ipallocator/interfaces.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/registry/core/service/ipallocator/ipallocator.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/registry/core/service/ipallocator/metrics.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/util/hash/hash.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/util/parsers/parsers.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/kubernetes/pkg/util/taints/taints.go is excluded by !**/vendor/**, !vendor/**
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (8)
  • go.mod
  • pkg/route/ingress/ingress.go
  • pkg/route/ingressip/service_ingressip_controller.go
  • pkg/route/ingressip/service_ingressip_controller_test.go
  • pkg/utils/ipallocator/README.md
  • pkg/utils/ipallocator/allocator.go
  • pkg/utils/ipallocator/ipallocator.go
  • pkg/utils/ipallocator/ipallocator_test.go
💤 Files with no reviewable changes (1)
  • go.mod
✅ Files skipped from review due to trivial changes (1)
  • pkg/utils/ipallocator/README.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • pkg/route/ingress/ingress.go
  • pkg/route/ingressip/service_ingressip_controller.go

}

func TestAllocateSpecific(t *testing.T) {
r, _ := NewInMemory(parseCIDR(t, "172.16.0.0/28"))
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 | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="pkg/utils/ipallocator/ipallocator_test.go"

if [ ! -f "$file" ]; then
  echo "Missing file: $file" >&2
  exit 1
fi

echo "== Lines 1-220: $file =="
nl -ba "$file" | sed -n '1,220p'

echo
echo "== Lines containing 'NewInMemory' / 'Allocate(' =="
rg -n "NewInMemory\\(|Allocate\\(" "$file" || true

echo
echo "== Lines where errors are assigned to '_' =="
rg -n ":=\\s*.*_,\\s*\\w|_,\\s*_\\s*[:=]|\\s*_,\\s*_\\s*:=" "$file" || true

Repository: openshift/route-controller-manager

Length of output: 201


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="pkg/utils/ipallocator/ipallocator_test.go"
sed -n '1,1p' "$file" >/dev/null 2>&1 || { echo "Missing/unreadable: $file" >&2; exit 1; }

echo "== Relevant line ranges (1-220): $file =="
cat -n "$file" | sed -n '1,220p'

echo
echo "== Lines containing 'NewInMemory(' or 'Allocate(' =="
rg -n "NewInMemory\\(|Allocate\\(" "$file" || true

echo
echo "== Lines where an error is discarded with '_' (common patterns) =="
rg -n "NewInMemory\\(.*\\)\\s*$|\\:=\\s*[^\\n]*_,\\s*[^\\n]*$|\\:=\\s*[^\\n]*\\_,\\s*[^\\n]*$|\\,\\s*_\\s*[:=]|\\b_\\s*[:=]" "$file" || true

Repository: openshift/route-controller-manager

Length of output: 6994


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="pkg/utils/ipallocator/ipallocator_test.go"

echo "== Exact discarded-constructor error patterns =="
rg -n "r, _ := NewInMemory" "$file" || true

echo
echo "== Allocate calls that ignore returned error (r.Allocate(…)) =="
rg -n "^\s*r\.Allocate\(" "$file" || true

echo
echo "== Allocate calls with error checks (looking for := or if err :=) =="
rg -n "Allocate\\(.*\\)\\s*\\{|if .*Allocate|:= .*Allocate|err := .*Allocate|_=.*Allocate" "$file" || true

echo
echo "== Show around each match for context =="
for m in $(rg -n "r, _ := NewInMemory|^\s*r\.Allocate\(" "$file" | cut -d: -f1 | sort -n | uniq); do
  echo "--- Context around line $m ---"
  start=$((m-3)); end=$((m+3))
  sed -n "${start},${end}p" "$file" | cat -n | head -n 10
done

Repository: openshift/route-controller-manager

Length of output: 4315


Stop discarding errors from NewInMemory() and Allocate() in ipallocator tests.

In pkg/utils/ipallocator/ipallocator_test.go, multiple tests ignore constructor errors (r, _ := NewInMemory(...) at lines 45, 57, 76, 94, 101, 113, 125, 139, 146, 153) and also ignore the returned error from allocation (r.Allocate(ip) at lines 79 and 116). These can hide allocator regressions and leave later assertions validating the wrong state—fail the test on every setup/allocation error instead of using _.

🤖 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/utils/ipallocator/ipallocator_test.go` at line 45, Replace the ignored
error returns from NewInMemory(...) and r.Allocate(...) in the ipallocator tests
so failures surface immediately: after calling NewInMemory(...) (symbol
NewInMemory) check the returned error and fail the test (e.g., t.Fatalf or
require.NoError) instead of using “_”, and likewise check the error returned by
Allocate (symbol Allocate) and fail the test on error; apply this change to
every test that currently discards those errors so setup/allocation errors break
the test immediately.

Comment on lines +168 to +184
func (r *Range) contains(ip net.IP) (bool, int) {
if !r.net.Contains(ip) {
return false, 0
}

offset := calculateIPOffset(r.base, ip)
if offset < 0 || offset >= r.max {
return false, 0
}
return true, offset
}

// calculateIPOffset calculates the integer offset of ip from base such that
// base + offset = ip. It requires ip >= base.
func calculateIPOffset(base *big.Int, ip net.IP) int {
return int(big.NewInt(0).Sub(netutils.BigForIP(ip), base).Int64())
}
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Jun 2, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the target file and print the relevant sections
echo "=== pkg/utils/ipallocator/ipallocator.go (contains + calculateIPOffset + Range fields) ==="
sed -n '1,260p' pkg/utils/ipallocator/ipallocator.go | nl -ba | sed -n '130,230p'

echo "=== pkg/utils/ipallocator/ipallocator.go (NewInMemory and IPv6 capping) ==="
sed -n '1,260p' pkg/utils/ipallocator/ipallocator.go | nl -ba | sed -n '1,150p'

echo "=== Downstream usage: service_ingressip_controller.go around 315-341 ==="
sed -n '280,380p' pkg/route/ingressip/service_ingressip_controller.go | nl -ba | sed -n '20,140p'

echo "=== Find where ErrNotInRange is produced/propagated in ipallocator ==="
rg -n "ErrNotInRange|NotInRange" pkg/utils/ipallocator/ipallocator.go pkg/utils/ipallocator -S

echo "=== Ensure Allocate/Release/Has use contains() as claimed ==="
rg -n "contains\\(" pkg/utils/ipallocator/ipallocator.go -S

Repository: openshift/route-controller-manager

Length of output: 230


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== File existence ==="
ls -la pkg/utils/ipallocator/ipallocator.go
ls -la pkg/route/ingressip/service_ingressip_controller.go

echo "=== pkg/utils/ipallocator/ipallocator.go (around contains/calculateIPOffset) ==="
python3 - <<'PY'
import itertools
path="pkg/utils/ipallocator/ipallocator.go"
start, end = 120, 220
with open(path,'r',encoding='utf-8') as f:
    for i,line in enumerate(f, start=1):
        if start <= i <= end:
            print(f"{i:5d}: {line.rstrip()}")
        if i > end:
            break
PY

echo "=== pkg/utils/ipallocator/ipallocator.go (around NewInMemory) ==="
python3 - <<'PY'
import itertools
path="pkg/utils/ipallocator/ipallocator.go"
start, end = 1, 160
with open(path,'r',encoding='utf-8') as f:
    for i,line in enumerate(f, start=1):
        if start <= i <= end:
            print(f"{i:5d}: {line.rstrip()}")
        if i > end:
            break
PY

echo "=== Downstream usage: service_ingressip_controller.go around 315-341 ==="
python3 - <<'PY'
path="pkg/route/ingressip/service_ingressip_controller.go"
start, end = 280, 380
with open(path,'r',encoding='utf-8') as f:
    for i,line in enumerate(f, start=1):
        if start <= i <= end:
            print(f"{i:5d}: {line.rstrip()}")
        if i > end:
            break
PY

echo "=== Search for ErrNotInRange production ==="
rg -n "ErrNotInRange" pkg/utils/ipallocator -S

echo "=== Search for contains() usage in ipallocator ==="
rg -n "contains\\(" pkg/utils/ipallocator/ipallocator.go -S

Repository: openshift/route-controller-manager

Length of output: 13671


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== pkg/utils/ipallocator/ipallocator_test.go (around existing tests) ==="
python3 - <<'PY'
path="pkg/utils/ipallocator/ipallocator_test.go"
start, end = 1, 220
with open(path,'r',encoding='utf-8') as f:
    for i,line in enumerate(f, start=1):
        if start <= i <= end:
            print(f"{i:5d}: {line.rstrip()}")
        if i > end:
            break
PY

echo "=== allocation map implementation: search for newAllocationMapWithOffset ==="
rg -n "newAllocationMapWithOffset|type allocation|allocatorInterface|Allocate\\(offset\\)" pkg/utils/ipallocator -S

echo "=== show file(s) containing newAllocationMapWithOffset and allocatorInterface ==="
fd -a "ipallocator" pkg/utils/ipallocator 2>/dev/null || true
files=$(rg -l "newAllocationMapWithOffset" pkg/utils/ipallocator -S || true)
echo "Files: $files"
for f in $files; do
  echo "---- $f (relevant lines) ----"
  python3 - <<PY
path="$f"
start,end=1,260
with open(path,'r',encoding='utf-8') as fh:
    for i,line in enumerate(fh, start=1):
        if i>=1 and i<=260:
            pass
PY
done

# Print the whole relevant files but capped by size using sed line ranges
for f in $files; do
  echo "---- $f (first 260 lines with numbers) ----"
  python3 - <<'PY'
import sys
path=sys.argv[1]
start=1; end=260
with open(path,'r',encoding='utf-8') as f:
    for i,line in enumerate(f, start=1):
        if start <= i <= end:
            print(f"{i:5d}: {line.rstrip()}")
        if i>end:
            break
PY "$f"
done

Repository: openshift/route-controller-manager

Length of output: 7432


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== pkg/utils/ipallocator/allocator.go (around allocator + bitmap Allocate/Release) ==="
python3 - <<'PY'
path="pkg/utils/ipallocator/allocator.go"
# Print key sections; adjust ranges if needed.
ranges=[(1,220),(220,420)]
for start,end in ranges:
    with open(path,'r',encoding='utf-8') as f:
        for i,line in enumerate(f, start=1):
            if start<=i<=end:
                print(f"{i:5d}: {line.rstrip()}")
            if i>end:
                break
PY

echo "=== pkg/utils/ipallocator/allocator.go: search for bounds checks in Allocate/Release/Has ==="
rg -n "func \\(.*\\) (Allocate|Release|Has)\\(" pkg/utils/ipallocator/allocator.go -S || true
rg -n "offset|max" pkg/utils/ipallocator/allocator.go -S | head -n 120

Repository: openshift/route-controller-manager

Length of output: 8790


🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n "calculateIPOffset" pkg/utils/ipallocator -S

Repository: openshift/route-controller-manager

Length of output: 374


Avoid big.Int truncation in IPv6 offset bounds checks.
pkg/utils/ipallocator/ipallocator.go computes the offset using Int64()/int (calculateIPOffset), then uses that truncated value for the offset < 0 || offset >= r.max check in (*Range).contains(). For large IPv6 CIDRs, the big.Int delta can overflow int64 and wrap into a small in-range int, causing contains() to return ok=true and making Allocate() succeed instead of returning *ErrNotInRange (which service_ingressip_controller.go relies on to trigger reallocation).

Suggested fix
 func (r *Range) contains(ip net.IP) (bool, int) {
 	if !r.net.Contains(ip) {
 		return false, 0
 	}
 
-	offset := calculateIPOffset(r.base, ip)
-	if offset < 0 || offset >= r.max {
+	offset := big.NewInt(0).Sub(netutils.BigForIP(ip), r.base)
+	if offset.Sign() < 0 || offset.Cmp(big.NewInt(int64(r.max))) >= 0 {
 		return false, 0
 	}
-	return true, offset
-}
-
-// calculateIPOffset calculates the integer offset of ip from base such that
-// base + offset = ip. It requires ip >= base.
-func calculateIPOffset(base *big.Int, ip net.IP) int {
-	return int(big.NewInt(0).Sub(netutils.BigForIP(ip), base).Int64())
+	return true, int(offset.Int64())
 }
🤖 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/utils/ipallocator/ipallocator.go` around lines 168 - 184, The contains()
logic currently truncates the big.Int delta to int64/int via calculateIPOffset,
which can overflow for large IPv6 ranges; change calculateIPOffset to return the
full *big.Int delta (netutils.BigForIP(ip).Sub(base)) and update Range.contains
to compare that big.Int directly: check delta.Sign() < 0 or
delta.Cmp(big.NewInt(0).SetInt64(int64(r.max))) >= 0 to decide out-of-range, and
only after those checks convert the delta to a Go int (ensuring it fits, e.g.
via delta.IsInt64() and bounds against runtime.MaxInt) before returning the
offset; update references to calculateIPOffset and the return types accordingly
to avoid any Int64()/int truncation.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@coderabbitai this code was copied from the dropped vendor vendor/k8s.io/kubernetes/pkg/registry/core/service/ipallocator and I don't wanna change any behavior

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Resolve my own review comment on the PR
gh api graphql -f query='
{
  repository(owner: "openshift", name: "route-controller-manager") {
    pullRequest(number: 92) {
      reviewThreads(first: 50) {
        nodes {
          id
          isResolved
          comments(first: 1) {
            nodes {
              author { login }
              body
            }
          }
        }
      }
    }
  }
}'

Length of output: 12923


🏁 Script executed:

#!/bin/bash
# Resolve my own review thread about big.Int truncation
gh api graphql -f query='
mutation {
  resolveReviewThread(input: { threadId: "PRRT_kwDOHzQul86GhoJ5" }) {
    thread {
      id
      isResolved
    }
  }
}'

Length of output: 735



@rikatz, understood — I'll defer to the upstream behavior since this is a faithful copy of vendor/k8s.io/kubernetes/pkg/registry/core/service/ipallocator. I wasn't able to resolve the comment programmatically due to permissions, but you can dismiss it manually.


✏️ Learnings added
Learnt from: rikatz
Repo: openshift/route-controller-manager PR: 92
File: pkg/utils/ipallocator/ipallocator.go:168-184
Timestamp: 2026-06-02T18:25:50.708Z
Learning: In `pkg/utils/ipallocator/ipallocator.go` and `pkg/utils/ipallocator/allocator.go` (repository: openshift/route-controller-manager), the IP allocator implementation was intentionally copied verbatim from the dropped vendor path `vendor/k8s.io/kubernetes/pkg/registry/core/service/ipallocator`. The maintainer does not want to diverge from upstream behavior, so review suggestions that alter logic (e.g., `big.Int` truncation in `calculateIPOffset`/`contains()`) should not be raised against this code.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

"k8s.io/kubernetes/pkg/registry/core/service/allocator"
"k8s.io/kubernetes/pkg/registry/core/service/ipallocator"

"github.com/openshift/route-controller-manager/pkg/utils/ipallocator"
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

this could be github.com/cilium/ipam which is also a copy, we can consider it

@rikatz
Copy link
Copy Markdown
Member Author

rikatz commented Jun 3, 2026

/retest-required
@coderabbitai I want you to verify the dropped dependency from ipallocator and the fact we copied the code, and verify if the code semantics that we are using now is equal, works fine, is not a breaking change, do a line by line analysis

@rikatz
Copy link
Copy Markdown
Member Author

rikatz commented Jun 3, 2026

/retest prow/e2e-gcp

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 3, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
echo "=== pkg/utils/ipallocator/ipallocator.go ==="
cat pkg/utils/ipallocator/ipallocator.go

echo ""
echo "=== pkg/utils/ipallocator/allocator.go ==="
cat pkg/utils/ipallocator/allocator.go

echo ""
echo "=== pkg/utils/ipallocator/ipallocator_test.go ==="
cat pkg/utils/ipallocator/ipallocator_test.go

echo ""
echo "=== pkg/utils/ipallocator/README.md ==="
cat pkg/utils/ipallocator/README.md

echo ""
echo "=== pkg/route/ingressip/service_ingressip_controller.go ==="
cat pkg/route/ingressip/service_ingressip_controller.go

echo ""
echo "=== pkg/route/ingressip/service_ingressip_controller_test.go ==="
cat pkg/route/ingressip/service_ingressip_controller_test.go

echo ""
echo "=== Searching for any remaining k8s.io/kubernetes imports ==="
rg "k8s.io/kubernetes" --type=go -n

echo ""
echo "=== Searching for ipallocator usages in the codebase ==="
rg "ipallocator" --type=go -n -A2 -B2

echo ""
echo "=== Check if there's a vendor copy of the original ==="
find . -path "*/registry/core/service/ipallocator*" 2>/dev/null | head -20

echo ""
echo "=== Check go.mod for remaining k8s.io/kubernetes ==="
cat go.mod | grep -E "k8s.io/kubernetes|ipallocator"

Length of output: 63945



@rikatz Here is the full line-by-line semantic analysis.


Dropped dependency verification

rg "k8s.io/kubernetes" --type=go  →  (no matches)

k8s.io/kubernetes is completely gone from all Go source files. The only remaining k8s-flavoured dependencies are k8s.io/client-go, k8s.io/apimachinery, k8s.io/utils/net, etc. — all standalone modules.


pkg/utils/ipallocator/ipallocator.go — semantic analysis

NewInMemory(cidr *net.IPNet)

Step New code Upstream logic Equivalent?
Compute range size netutils.RangeSize(cidr) same call
Compute numeric base netutils.BigForIP(cidr.IP) same call
IPv4 broadcast skip max-- max--
IPv6 cap if max > 65536 { max = 65536 } same cap
Skip .0 network address base.Add(base, big.NewInt(1)); max-- same
Clamp negative max if max < 0 { max = 0 } same guard
Allocation map offset calculateRangeOffset(cidr) same function

calculateRangeOffset

Constants min=16, max=256, step=16 are byte-for-byte identical to the upstream. Formula min(max(min, cidrSize/step), max), returns 0 when cidrSize <= min. ✅

contains(ip)

net.Contains(ip)  →  calculateIPOffset(base, ip)  →  bounds [0, r.max)

Same logic as upstream. ✅

calculateIPOffset

int(big.NewInt(0).Sub(netutils.BigForIP(ip), base).Int64())

Uses big.Int arithmetic then converts to int64int. Safe for all practical CIDR ranges (IPv6 capped at 65536; IPv4 never exceeds ~4B which fits in int64). Verbatim from upstream. ✅

Public methods — error contract

Method Returned errors Controller checks for Contract preserved?
Allocate(ip) *ErrNotInRange, ErrAllocated err.(*ipallocator.ErrNotInRange) type-assert
AllocateNext() ErrFull err == ipallocator.ErrFull
Release(ip) nil if out-of-range; underlying bitmap error controller logs any non-nil
Has(ip) false if out-of-range direct bool use
Free() int direct int use

pkg/utils/ipallocator/allocator.go — semantic analysis

allocationBitmap

Method Behaviour Notes
Allocate(offset) bounds check → check bit → set bit + count++ → return (true, nil) or (false, nil) No error on double-alloc, upper layer (ipallocator.go) converts (false, nil)ErrAllocated. ✅
AllocateNext() delegates to strategy.AllocateBit → set bit + count++ → (offset, true, nil) or (0, false, nil) Upper layer converts falseErrFull. ✅
Release(offset) no-op if bit=0; otherwise clear bit + count--
Has(offset) returns allocated.Bit(offset) == 1
Free() max - count

randomScanStrategyWithOffset.AllocateBit

  1. Returns (0, false) immediately when count >= max (full).
  2. Computes subrangeMax = max - offset (the "dynamic" upper block).
  3. Picks random start in [0, subrangeMax), scans forward wrapping within upper block.
  4. If upper block exhausted, falls back to lower block [0, offset).
  5. Guards rand.Intn(0) panic with if rss.offset > 0 before the fallback scan. ✅

This preserves the upstream semantics: IPs in the "static allocation" zone (lower block) are withheld from AllocateNext until the upper block is full, matching the original randomScanStrategyWithOffset.


Controller changes (service_ingressip_controller.go)

1. ipallocator.NewInMemory(ipNet) → no breaking change

Provides identical in-memory allocation over the same *net.IPNet. The returned *ipallocator.Range exposes the same method set used by the controller. ✅

2. cache.DeletionHandlingMetaNamespaceKeyFunc replaces controller.KeyFunc

In k8s.io/kubernetes/pkg/controller, KeyFunc is literally defined as:

var KeyFunc = cache.DeletionHandlingMetaNamespaceKeyFunc

The new code calls cache.DeletionHandlingMetaNamespaceKeyFunc directly — same function, different import path. Used in 3 places: enqueueChange, processInitialSync (pending services loop), clearOldAllocation. All semantically identical. ✅

3. scheme.Scheme (k8s.io/client-go/kubernetes/scheme) replaces legacyscheme.Scheme

The legacy scheme was the full monorepo scheme. client-go/kubernetes/scheme registers all core API types including v1.Service and v1.EventSource, which is all the event recorder needs. No functional change for IngressIP controller event recording. ✅


Test file change

// Before
informers.NewSharedInformerFactory(client, controller.NoResyncPeriodFunc())

// After
informers.NewSharedInformerFactory(client, 0)

controller.NoResyncPeriodFunc() is defined as returning 0 (a zero time.Duration). Passing 0 directly is byte-for-byte the same value. ✅


Removed features (README accuracy check)

All 6 listed removals (metrics, dry-run, snapshot/restore, IPFamily, factory pattern, unused methods) are confirmed absent from the new code and are not referenced anywhere in the codebase. The controller only ever called NewInMemory/Allocate/AllocateNext/Release/Has/Free — all of which are preserved. ✅


Verdict

This is not a breaking change. The copied code is semantically equivalent to the upstream k8s.io/kubernetes ipallocator for every code path exercised by the IngressIP controller. The public API contract (error sentinels, method signatures, range boundary logic) is fully preserved, and the dependency on the Kubernetes monorepo is cleanly eliminated.


🧠 Learnings used
Learnt from: rikatz
Repo: openshift/route-controller-manager PR: 92
File: pkg/utils/ipallocator/ipallocator.go:168-184
Timestamp: 2026-06-02T18:25:54.551Z
Learning: In `pkg/utils/ipallocator/ipallocator.go` and `pkg/utils/ipallocator/allocator.go` (repository: openshift/route-controller-manager), the IP allocator implementation was intentionally copied verbatim from the dropped vendor path `vendor/k8s.io/kubernetes/pkg/registry/core/service/ipallocator`. The maintainer does not want to diverge from upstream behavior, so review suggestions that alter logic (e.g., `big.Int` truncation in `calculateIPOffset`/`contains()`) should not be raised against this code.

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Jun 3, 2026

@rikatz: The /retest command does not accept any targets.
The following commands are available to trigger required jobs:

/test e2e-aws-ovn
/test e2e-aws-upgrade
/test e2e-gcp
/test e2e-hypershift
/test images
/test okd-scos-images
/test unit
/test verify
/test verify-deps

The following commands are available to trigger optional jobs:

/test okd-scos-e2e-aws-ovn
/test security

Use /test all to run the following jobs that were automatically triggered:

pull-ci-openshift-route-controller-manager-main-e2e-aws-ovn
pull-ci-openshift-route-controller-manager-main-e2e-aws-upgrade
pull-ci-openshift-route-controller-manager-main-e2e-gcp
pull-ci-openshift-route-controller-manager-main-e2e-hypershift
pull-ci-openshift-route-controller-manager-main-images
pull-ci-openshift-route-controller-manager-main-okd-scos-images
pull-ci-openshift-route-controller-manager-main-security
pull-ci-openshift-route-controller-manager-main-unit
pull-ci-openshift-route-controller-manager-main-verify
pull-ci-openshift-route-controller-manager-main-verify-deps
Details

In response to this:

/retest prow/e2e-gcp

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.

@bentito
Copy link
Copy Markdown

bentito commented Jun 3, 2026

/assign @Miciah @bentito

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Jun 3, 2026

@rikatz: all tests passed!

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

approved Indicates a PR has been approved by an approver from all required OWNERS files. jira/severity-low Referenced Jira bug's severity is low for the branch this PR is targeting. jira/valid-bug Indicates that a referenced Jira bug is valid 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.

4 participants