Skip to content

feat: Add support for server-side content negotiation#7531

Open
ash-thakur-rh wants to merge 6 commits intofabric8io:mainfrom
ash-thakur-rh:feat-partial-response
Open

feat: Add support for server-side content negotiation#7531
ash-thakur-rh wants to merge 6 commits intofabric8io:mainfrom
ash-thakur-rh:feat-partial-response

Conversation

@ash-thakur-rh
Copy link
Copy Markdown
Member

@ash-thakur-rh ash-thakur-rh commented Mar 6, 2026

Description

Adds support for two Kubernetes server-side content negotiation formats via the Accept header, allowing clients to receive lightweight or display-optimized representations of resources without changing the API endpoint. Both
features work across all resource types: built-in resources, CRDs, and custom resources.

Fixes #7451
Fixes #5716


PartialObjectMetadata

Fetches only the metadata of a resource (no spec, no status). The server strips the heavy fields before sending, significantly reducing payload size. Useful in controllers and operators that need to watch or list many resources but only care about labels, annotations, UIDs, or resource versions.

Accept header: application/json;as=PartialObjectMetadata;g=meta.k8s.io;v=v1

New model classes (kubernetes-model-core):

  • PartialObjectMetadata: implements HasMetadata, contains apiVersion, kind, metadata
  • PartialObjectMetadataList: extends DefaultKubernetesResourceList<PartialObjectMetadata>

New DSL interfaces (kubernetes-client-api):

  • MetadataGettable: getAsPartialObjectMetadata() → returns null on 404, consistent with get()
  • MetadataListable: listAsPartialObjectMetadata() and listAsPartialObjectMetadata(ListOptions)

Wired into:

  • Resource<T> extends MetadataGettable
  • FilterWatchListDeletable<T,L,R> extends MetadataListable

Table

Fetches a server-rendered table: the same format used by kubectl get. The server returns columnDefinitions (headers) and rows (one per resource), with each row's cells aligned by index with columnDefinitions. Column names and count are decided by the server based on resource type; priority == 0 columns are the default view, priority > 0 are wide columns (kubectl get -o wide).

Accept header: application/json;as=Table;v=v1;g=meta.k8s.io

New model classes (kubernetes-model-core):

  • Table: columnDefinitions, rows, metadata (ListMeta); annotated with @JsonIgnoreProperties(ignoreUnknown = true) to tolerate server-side field additions
  • TableColumnDefinition: name, type, format, description, priority
  • TableRow(cells): List<Object>, optional object: RawExtension; annotated with @JsonIgnoreProperties(ignoreUnknown = true) to handle conditions and other optional server fields

New DSL interfaces (kubernetes-client-api):

  • TableGettable: getAsTable() → returns null on 404
  • TableListable: listAsTable() and listAsTable(ListOptions)

Wired into:

  • Resource<T> extends TableGettable
  • FilterWatchListDeletable<T,L,R> extends TableListable

Shared Implementation Details

  • BaseOperation implements all four methods with the appropriate Accept headers
  • getAsPartialObjectMetadata() and getAsTable() both catch HTTP 404 and return null, matching the behaviour of get()
  • ResourceAdapter delegates getAsPartialObjectMetadata() and getAsTable() to the wrapped resource
  • All methods support the full filter chain: inNamespace(), inAnyNamespace(), withLabel(), withField(), withName(), and ListOptions (pagination, label/field selectors)

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change
  • Chore (non-breaking change which doesn't affect codebase;
    test, version modification, documentation, etc.)

Checklist

  • Code contributed by me aligns with current project license: Apache 2.0
  • I Added CHANGELOG entry regarding this change
  • I have implemented unit tests to cover my changes
  • I have added/updated the javadocs and other documentation accordingly
  • No new bugs, code smells, etc. in SonarCloud report
  • I tested my code in Kubernetes
  • I tested my code in OpenShift

@ash-thakur-rh
Copy link
Copy Markdown
Member Author

ash-thakur-rh commented Mar 6, 2026

image tested with k8s, Attaching screenshots

Comment on lines +44 to +47
server.expect().get()
.withPath("/api/v1/namespaces/default/pods/my-pod")
.andReturn(200, podPartialMetadata("my-pod", "default", "app", "backend", "version", "v1"))
.once();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

AS discussed internally.
The HTTP mock should return different objects depending on the header provided. IF the header matches the one for partial metadata, the server should respond only with metadata fields, if not it should return everything.

(You can create this with a proper function in the expectation that checks the headers -I think-)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If you switch to use KubeApiTest, you won't even need to mock the response and we can be sure that the Kube API behaves as expected

Comment on lines +57 to +59
assertThat(result.getMetadata().getLabels())
.containsEntry("app", "backend")
.containsEntry("version", "v1");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Once the previous comment is implemented, we should actually have an assertion to check that the other fields in the Pod are empty (spec, status)

@ash-thakur-rh ash-thakur-rh force-pushed the feat-partial-response branch from 1375e21 to 2264601 Compare April 17, 2026 09:51
@ash-thakur-rh ash-thakur-rh force-pushed the feat-partial-response branch from 2264601 to f1c128a Compare April 17, 2026 09:53
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The test is good, but I'm not sure this is the right place.
Ideally this should be in a different module. Tests here are supposed to be testing kubeapitest functionality and not kubernetes client implementations.

@manusa
Copy link
Copy Markdown
Member

manusa commented May 4, 2026

The last commit you created is plainly wrong. It removed the Kube API tests and used mocks instead. That's not ok.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for server-side content negotiation (Table and PartialObjectMetadata responses) Add support for partial object metadata

2 participants