Skip to content

Conversation

@lhy1024
Copy link
Contributor

@lhy1024 lhy1024 commented Jan 15, 2026

What problem does this PR solve?

Issue Number: Ref #9764

What is changed and how does it work?

Check List

Tests

  • Unit test

Release note

None.

Summary by CodeRabbit

  • New Features

    • Create affinity groups with an option to skip existing ones (skip_exist_check) — responses include existing and newly created groups
    • Retrieve affinity groups selectively via an ids query parameter (server) or GetAffinityGroups API (client); IDs are URL-escaped and validated
    • Client API accepts creation options (e.g., WithSkipExistCheck) and variadic creation call
  • Tests

    • Added tests for skip-existing creation, ID-based retrieval, invalid/empty ID handling, plus healthy-store test helpers

@ti-chi-bot
Copy link
Contributor

ti-chi-bot bot commented Jan 15, 2026

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@ti-chi-bot ti-chi-bot bot added do-not-merge/needs-linked-issue do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. release-note-none Denotes a PR that doesn't merit a release note. dco-signoff: yes Indicates the PR's author has signed the dco. labels Jan 15, 2026
@coderabbitai
Copy link

coderabbitai bot commented Jan 15, 2026

📝 Walkthrough

Walkthrough

Adds optional "skip existing" behavior to affinity-group creation and an IDs filter for retrieval across client HTTP, server handlers, scheduling/affinity core, txn logic, and tests; introduces client options, group ID parsing/collection helpers, and a CreateAffinityGroupsIfNotExists codepath.

Changes

Cohort / File(s) Summary
HTTP Client
client/http/interface.go
Made CreateAffinityGroups variadic with CreateAffinityGroupsOption and WithSkipExistCheck; added createAffinityGroupsOptions; appended ?skip_exist_check=true when enabled; added GetAffinityGroups(ctx, groupIDs) building URL-escaped ID query.
Server API Handlers
server/apiv2/handlers/affinity.go, pkg/mcs/scheduling/server/apis/v1/api.go
Parsed skip_exist_check for create (routes to CreateAffinityGroupsIfNotExists when true) and added ids query param for selective retrieval; updated handlers to use CollectGroupStates or CollectAllGroupStates and return mapped responses; added swagger annotations and validation.
Affinity Core / Parsing
pkg/schedule/affinity/parse.go
Added groupStateProvider interface and helpers: CollectAllGroupStates, ParseGroupIDs, CollectGroupStates to trim, dedupe, validate, and collect group states by IDs (returns ordered/validated IDs or error).
Affinity Transactions
pkg/schedule/affinity/txn.go
Added CreateAffinityGroupsIfNotExists and createGroupsWithSkipExisting; when skipping, filters out already-existing groups under read lock and applies validation, rule creation, storage, and in-memory updates to filtered data; preserves original behavior when not skipping.
Server API Tests
tests/server/apiv2/handlers/affinity_test.go
Added mustPutHealthyStore helper; new tests: TestAffinityGroupCreateSkipExistCheck, TestAffinityGroupCreateSkipExistCheckInvalidBool, TestAffinityListWithIDs, TestAffinityListWithInvalidIDs, TestAffinityListWithEmptyID; adjusted store setup in related tests.
Misc
go.mod
Dependencies/imports updated to support new code and tests.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant APIHandler as "API Handler"
    participant Manager as "Affinity Manager"
    participant Storage as "Group State Storage"

    Client->>APIHandler: POST /affinity-groups?skip_exist_check=true (groups)
    APIHandler->>Manager: CreateAffinityGroupsIfNotExists(changes)
    Manager->>Storage: GetAllAffinityGroupStates()
    Storage-->>Manager: existingStates
    Manager->>Manager: Filter out existing groups
    Manager->>Manager: Validate & build label rules
    Manager->>Storage: Save new groups
    Storage-->>Manager: persist result
    Manager-->>APIHandler: created + existing states
    APIHandler-->>Client: 200 {all requested groups}
Loading
sequenceDiagram
    participant Client
    participant APIHandler as "API Handler"
    participant Parser as "Parser (parse.go)"
    participant Provider as "Group State Provider"

    Client->>APIHandler: GET /affinity-groups?ids=id1,id2
    APIHandler->>Parser: ParseGroupIDs([id1,id2])
    Parser-->>APIHandler: validated IDs
    APIHandler->>Provider: CollectGroupStates(provider, ids)
    Provider->>Provider: GetAffinityGroupState(id) [per id]
    Provider-->>APIHandler: map[id]->GroupState
    APIHandler-->>Client: 200 {map of requested group states}
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

size/XXL, lgtm

Suggested reviewers

  • okJiang
  • rleungx
  • JmPotato

Poem

🐰 I hopped through code and trimmed each id,
Skipped old burrows where duplicates hid,
New options and lists, tidy rows in a line,
Groups gathered neat where the logic did shine.
🥕 Hop, hop, hooray — affinity's fine!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description check ⚠️ Warning PR description is missing critical information and contains placeholder content; commit message is empty. Fill in the 'What is changed and how does it work?' section with a detailed explanation of the changes; provide a specific issue number or replace with the actual GitHub issue reference; add a meaningful commit message describing the changes.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main changes: adding ID filtering and skip-exist create options for affinity groups.
Docstring Coverage ✅ Passed Docstring coverage is 90.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@ti-chi-bot ti-chi-bot bot added the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Jan 15, 2026
@ti-chi-bot ti-chi-bot bot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. labels Feb 9, 2026
@lhy1024 lhy1024 marked this pull request as ready for review February 9, 2026 12:25
@ti-chi-bot ti-chi-bot bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Feb 9, 2026
@codecov
Copy link

codecov bot commented Feb 9, 2026

Codecov Report

❌ Patch coverage is 68.96552% with 45 lines in your changes missing coverage. Please review.
✅ Project coverage is 78.70%. Comparing base (31fc48f) to head (f917775).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #10157      +/-   ##
==========================================
- Coverage   78.73%   78.70%   -0.04%     
==========================================
  Files         522      523       +1     
  Lines       70270    70391     +121     
==========================================
+ Hits        55330    55400      +70     
- Misses      10938    10984      +46     
- Partials     4002     4007       +5     
Flag Coverage Δ
unittests 78.70% <68.96%> (-0.04%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

@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

🤖 Fix all issues with AI agents
In `@client/http/interface.go`:
- Around line 1273-1296: The Client interface is missing declarations for
methods implemented on *client: add method signatures for
CreateAffinityGroupsWithSkipExistCheck(ctx context.Context, affinityGroups
map[string][]AffinityGroupKeyRange) (map[string]*AffinityGroupState, error) and
GetAffinityGroups(ctx context.Context) (map[string]*AffinityGroupState, error)
to the Client interface so callers using the interface can access these
implementations; update the interface block that declares other affinity group
methods to include these two signatures matching the concrete implementations in
CreateAffinityGroupsWithSkipExistCheck and GetAffinityGroups.
🧹 Nitpick comments (2)
client/http/interface.go (1)

1273-1296: Consider extracting shared logic with CreateAffinityGroups.

CreateAffinityGroupsWithSkipExistCheck duplicates all of CreateAffinityGroups (lines 1247–1271) except for the URI suffix and request name. A small helper or an optional parameter could eliminate the duplication.

♻️ Sketch
-func (c *client) CreateAffinityGroups(ctx context.Context, affinityGroups map[string][]AffinityGroupKeyRange) (map[string]*AffinityGroupState, error) {
+func (c *client) createAffinityGroupsInternal(ctx context.Context, affinityGroups map[string][]AffinityGroupKeyRange, skipExistCheck bool) (map[string]*AffinityGroupState, error) {
 	reqGroups := make(map[string]CreateAffinityGroupInput, len(affinityGroups))
 	for groupID, ranges := range affinityGroups {
 		reqGroups[groupID] = CreateAffinityGroupInput{Ranges: ranges}
 	}
 	req := CreateAffinityGroupsRequest{AffinityGroups: reqGroups}
 	reqJSON, err := json.Marshal(req)
 	if err != nil {
 		return nil, errors.Trace(err)
 	}
+	uri := AffinityGroups
+	name := "CreateAffinityGroups"
+	if skipExistCheck {
+		uri += "?skip_exist_check=true"
+		name = "CreateAffinityGroupsWithSkipExistCheck"
+	}
 	var resp AffinityGroupsResponse
 	err = c.request(ctx, newRequestInfo().
-		WithName("CreateAffinityGroups").
-		WithURI(AffinityGroups).
+		WithName(name).
+		WithURI(uri).
 		WithMethod(http.MethodPost).
 		WithBody(reqJSON).
 		WithResp(&resp))
 	if err != nil {
 		return nil, err
 	}
 	return resp.AffinityGroups, nil
 }
+
+func (c *client) CreateAffinityGroups(ctx context.Context, affinityGroups map[string][]AffinityGroupKeyRange) (map[string]*AffinityGroupState, error) {
+	return c.createAffinityGroupsInternal(ctx, affinityGroups, false)
+}
+
+func (c *client) CreateAffinityGroupsWithSkipExistCheck(ctx context.Context, affinityGroups map[string][]AffinityGroupKeyRange) (map[string]*AffinityGroupState, error) {
+	return c.createAffinityGroupsInternal(ctx, affinityGroups, true)
+}
server/apiv2/handlers/affinity.go (1)

143-151: Minor: ErrBindJSON is a misleading wrapper for a query-parameter parsing error.

strconv.ParseBool failure isn't a JSON binding error. Consider using a more appropriate error, e.g., ErrAffinityGroupContent or a direct bad-request message, to avoid confusing operators reading logs.

Suggestion
 	if rawValue, ok := c.GetQuery("skip_exist_check"); ok {
 		parsed, err := strconv.ParseBool(rawValue)
 		if err != nil {
-			c.AbortWithStatusJSON(http.StatusBadRequest, errs.ErrBindJSON.Wrap(err).GenWithStackByCause().Error())
+			c.AbortWithStatusJSON(http.StatusBadRequest, "invalid skip_exist_check value: "+rawValue)
 			return
 		}
 		skipExistCheck = parsed
 	}

Signed-off-by: lhy1024 <admin@liudos.us>
@lhy1024 lhy1024 changed the title affinity: support ids query and skip-exist create affinity: add ids filtering and skip-exist create options Feb 10, 2026
@ti-chi-bot
Copy link
Contributor

ti-chi-bot bot commented Feb 10, 2026

@lhy1024: 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
pull-unit-test-next-gen-2 f917775 link true /test pull-unit-test-next-gen-2

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.

@ti-chi-bot ti-chi-bot bot added needs-cherry-pick-release-8.5 Should cherry pick this PR to release-8.5 branch. and removed do-not-merge/needs-linked-issue labels Feb 10, 2026
@ti-chi-bot ti-chi-bot bot added the needs-1-more-lgtm Indicates a PR needs 1 more LGTM. label Feb 10, 2026
@ti-chi-bot
Copy link
Contributor

ti-chi-bot bot commented Feb 10, 2026

[LGTM Timeline notifier]

Timeline:

  • 2026-02-10 10:20:56.183624948 +0000 UTC m=+266671.877764778: ☑️ agreed by okJiang.

@ti-chi-bot
Copy link
Contributor

ti-chi-bot bot commented Feb 10, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: okJiang

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

@ti-chi-bot ti-chi-bot bot added the approved label Feb 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved dco-signoff: yes Indicates the PR's author has signed the dco. needs-1-more-lgtm Indicates a PR needs 1 more LGTM. needs-cherry-pick-release-8.5 Should cherry pick this PR to release-8.5 branch. release-note-none Denotes a PR that doesn't merit a release note. size/XL Denotes a PR that changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants