Skip to content

Conversation

@pteranodan
Copy link
Contributor

@pteranodan pteranodan commented Dec 19, 2025

Summary

This PR introduces a generated client-go SDK for the NVIDIA Device API, enabling Kubernetes-native patterns (Informers, Listers, controller-runtime) over a node-local gRPC connection.

It also slightly refactors the internal protobuf representations in the api module to ensure seamless compatibility with the Kubernetes ecosystem without changing the core of the API.

Key Changes

1. API Module Refactor (api/)

Refactored the API layer to support stricter interface compliance and standard client machinery:

  • Object Model Alignment:
    • Formalizes metadata by moving fields into dedicated ObjectMeta and ListMeta message types to satisfy metav1 interface requirements without needing custom conversions.
    • Adds resource_version fields to enable the optimistic concurrency and Watch semantics required by K8s caching layers.
  • Go Type & Conversion Layer:
    • Introduces native Go types to serve as the internal object model, decoupling logic from the Protobuf wire format.
    • Code Generation: All helper generation (e.g., deepcopy methods) handled by a centralized code-generator library via make code-gen.

2. Go Client SDK (client-go/)

Adds a generated client that provides the standard client-go experience over a node-local gRPC connection via Unix domain sockets (UDS).

  • Components: Generated Clientset, Listers, and Informers.
  • Patterns: Enables users to drive logic using standard Informer caches and Reconciler loops.

3. Code Generation (code-generator)

Introduces a dedicated directory for managing all code generation:

  • Bash Library: Provides kube_codegen.sh, a reusable library for orchestrating generation of Go bindings, gRPC interfaces, helpers, and clients.
  • Custom Client Generator: Contains a modified client-gen which handles gRPC service mapping to the standard K8s client interfaces.

3. Documentation & Examples

  • Patterns: Provides three reference implementations: basic-client (foundational), streaming-daemon (Watch/Interceptors), and controller-shim (Informer Injection).
  • Testing: Includes a fake-server to mock the Device API for local development/verification.
  • Guides: Adds or updates README.md's, DEVELOPMENT.md's, and CONFIGURATION.md's for each component.

Future Extensibility

  • Expanding Capability: Adding write operations (e.g., Update, Patch) to existing resources only requires updating the // +genclient tags in the API module, implementing the corresponding service methods on the server.
    • Requires one time implementation of the corresponding methods in the modified client-gen machinery.
  • Onboarding New Types: Define new resources in the api module with standard markers will automatically generate the full stack: DeepCopy methods, Proto-to-Go conversions, Typed Clients, Informers, and Listers.

Type of Change

  • 🐛 Bug fix
  • ✨ New feature
  • 💥 Breaking change (Internal Protobuf refactor)
  • 📚 Documentation
  • 🔧 Refactoring
  • 🔨 Build/CI

Component(s) Affected

  • Core Services
  • Documentation/CI
  • Fault Management
  • Health Monitors
  • Janitor
  • Other: SDK / Examples

Testing

  • Tests pass locally (make test)
  • Manual testing completed:
    • Verified all 3 examples run correctly against the local fake-server.
  • No breaking changes (or documented)

Checklist

  • Self-review completed
  • Documentation updated (if needed)
  • Ready for review

Review Guidance

This PR includes a significant amount of generated code which is collapsed by default in the diff (via .gitattributes).

Files to Skip:

  • api/**/zz_generated.*.go (DeepCopy, Conversions, etc.)
  • *.pb.go (Protobuf bindings)
  • client-go/{client,informers,listers}/** (Standard K8s client machinery)

Focus Areas:

  • Core Logic: api/ (Go types), client-go/nvgrpc/ (Connection logic), and code-generator/
  • Reference Implementations: client-go/examples/

Summary by CodeRabbit

  • New Features

    • Added GPU device API types supporting Kubernetes-native resource definitions with status conditions and metadata
    • Added gRPC-based Go client library for local NVIDIA device state queries
    • Added Kubernetes informers and listers for GPU resource caching and watch capabilities
    • Added example implementations: basic client, controller integration, streaming daemon, and test server
    • Added comprehensive code generation toolchain for Kubernetes-style APIs backed by gRPC
  • Documentation

    • Added development guides for API and client-go modules
    • Added usage examples and deployment guidance

✏️ Tip: You can customize this high-level summary in your review settings.

@copy-pr-bot
Copy link

copy-pr-bot bot commented Dec 19, 2025

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 19, 2025

📝 Walkthrough

Walkthrough

This pull request introduces a complete Kubernetes-native Go client library for the NVIDIA Device API with gRPC transport over Unix domain sockets. It adds GPU CRD type definitions, protobuf schema updates, a versioned clientset with informers and listers, gRPC infrastructure utilities, multiple example applications, and a custom Kubernetes-style code generation system supporting both protocol buffers and Go client generation.

Changes

Cohort / File(s) Summary
API Type Definitions
api/device/v1alpha1/gpu_types.go, api/device/v1alpha1/gpu_types_test.go, api/device/v1alpha1/zz_generated.deepcopy.go
Added GPU, GPUList, GPUSpec, GPUStatus CRD types with deepcopy implementations and codegen markers for Kubernetes client generation.
Proto Definitions
api/proto/device/v1alpha1/gpu.proto
Updated schema with ObjectMeta, ListMeta structures and resource_version fields for ListGpusRequest and WatchGpusRequest.
Converters & Registration
api/device/v1alpha1/converter.go, api/device/v1alpha1/gpu_conversion.go, api/device/v1alpha1/register.go, api/device/v1alpha1/doc.go
Added bidirectional protobuf-to-Go type conversions, singleton converter implementation, and v1alpha1 API group registration.
Makefiles & Build
api/Makefile, client-go/Makefile, api/hack/update-codegen.sh, client-go/hack/update-codegen.sh
Restructured build workflow to consolidate code generation via code-gen target; introduced generation scripts invoking Kubernetes code generators.
Client Core
client-go/client/versioned/clientset.go, client-go/client/versioned/typed/device/v1alpha1/device_client.go, client-go/client/versioned/typed/device/v1alpha1/gpu.go
Implemented versioned clientset with gRPC-backed device client, GPUInterface with Get/List/Watch operations using proto converters.
Scheme & Registration
client-go/client/versioned/scheme/register.go, client-go/client/versioned/scheme/doc.go
Added runtime scheme initialization, codec factory, and AddToScheme for client-generated types.
Informers
client-go/informers/externalversions/factory.go, client-go/informers/externalversions/device/interface.go, client-go/informers/externalversions/device/v1alpha1/gpu.go, client-go/informers/externalversions/internalinterfaces/factory_interfaces.go
Implemented SharedInformerFactory with functional options, device group interface, GPUInformer with resync and namespace support.
Listers
client-go/listers/device/v1alpha1/gpu.go, client-go/listers/device/v1alpha1/expansion_generated.go
Added GPULister for querying cached GPU objects via indexer and label selectors.
gRPC Infrastructure
client-go/nvgrpc/config.go, client-go/nvgrpc/client_conn.go, client-go/nvgrpc/options.go, client-go/nvgrpc/interceptors.go, client-go/nvgrpc/watcher.go
Implemented Config with environment-driven defaults, ClientConnFor factory, DialOption functional pattern, error-logging interceptors, and Kubernetes watch adapter.
Examples
client-go/examples/basic-client/main.go, client-go/examples/controller-shim/main.go, client-go/examples/streaming-daemon/main.go, client-go/examples/fake-server/main.go, client-go/examples/*/README.md
Added reference implementations: basic list/get, controller-runtime integration, event-driven daemon, and mock server with simulated state transitions.
Code Generator
code-generator/cmd/client-gen/*, code-generator/kube_codegen.sh
Implemented custom client-gen, scheme-gen, and proto binding generators; added gen_proto_bindings, gen_helpers, gen_client entrypoints in kube_codegen.sh.
Generator Support
code-generator/cmd/client-gen/args/args.go, code-generator/cmd/client-gen/args/gvpackages.go, code-generator/cmd/client-gen/generators/util/tags.go
Added CLI argument parsing, group-version package handling, and genclient tag extraction/validation system.
Generator Implementations
code-generator/cmd/client-gen/generators/client_generator.go, code-generator/cmd/client-gen/generators/generator_for_*.go
Implemented generators for clientset, scheme, per-group clients, per-type clients, and expansion interfaces with gRPC transport support.
Versioning & Types
code-generator/cmd/client-gen/types/types.go, code-generator/cmd/client-gen/types/helpers.go, client-go/version/version.go
Added type abstractions for GroupVersion, ProtobufPackage, GroupVersionInfo; version helpers; and UserAgent builder.
Testing & Integration
client-go/tests/integration/device/v1alpha1/clientset_test.go, client-go/nvgrpc/*_test.go, api/device/v1alpha1/gpu_conversion_test.go
Added end-to-end clientset integration tests, nvgrpc unit tests (config, interceptors, options, watcher), and GPU conversion tests.
Documentation & Configuration
client-go/README.md, client-go/DEVELOPMENT.md, api/README.md, api/DEVELOPMENT.md, .coderabbit.yaml, .gitattributes, Makefile
Added READMEs, development guides, code review filters for generated code, linguist directives, and linting rules.
Dependency Management
api/go.mod, client-go/go.mod, code-generator/go.mod, .versions.yaml
Added/updated go.mod files with dependencies (k8s.io/apimachinery, controller-runtime, gRPC, etc.); versioned code-gen tools.
Boilerplate & Metadata
api/hack/boilerplate.go.txt, client-go/hack/boilerplate.go.txt, .gitignore
Added Apache 2.0 license headers for code generation and ignore patterns for generated binaries.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Application
    participant Clientset as versioned.Clientset
    participant DeviceClient as DeviceV1alpha1Client
    participant GPUInterface as gpus (GPUInterface)
    participant gRPC as gRPC Conn
    participant UDS as Device API<br/>(UDS)

    Client->>Clientset: NewForConfig(config)
    Clientset->>gRPC: nvgrpc.ClientConnFor(config)
    gRPC->>UDS: Dial (Unix domain socket)
    UDS-->>gRPC: Connection established
    gRPC-->>Clientset: *grpc.ClientConn
    Clientset-->>Client: *Clientset

    Client->>Clientset: DeviceV1alpha1()
    Clientset-->>Client: DeviceV1alpha1Client

    Client->>DeviceClient: GPUs()
    DeviceClient->>GPUInterface: newGPUs(client)
    GPUInterface-->>Client: GPUInterface

    Client->>GPUInterface: List(ctx, opts)
    GPUInterface->>gRPC: ListGpus(ctx, request)
    gRPC->>UDS: List GPUs over UDS
    UDS-->>gRPC: *pb.GpuList response
    gRPC-->>GPUInterface: Response received
    GPUInterface->>GPUInterface: FromProtoList(pb.GpuList)
    GPUInterface-->>Client: *devicev1alpha1.GPUList
Loading
sequenceDiagram
    participant Factory as SharedInformerFactory
    participant Informer as GPUInformer
    participant Lister as GPULister
    participant Cache as Indexer Cache
    participant Source as gRPC Source

    Factory->>Factory: Start()
    Factory->>Informer: Launch per-informer goroutine

    Informer->>Informer: defaultInformer()
    Informer->>Source: List/Watch via gRPC

    Source->>Source: Initial List snapshot
    Source-->>Informer: Items added to cache

    Informer->>Cache: Store objects in indexer
    Cache-->>Informer: Sync complete

    Factory->>Factory: WaitForCacheSync()
    Informer-->>Factory: HasSynced reports true

    Lister->>Cache: List(selector)
    Cache-->>Lister: Filtered objects
    Lister-->>Factory: Cached objects returned

    Source->>Informer: Watch event (MODIFIED)
    Informer->>Cache: Update indexer
    Cache->>Lister: Query reflects new state
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Poem

🐰 Hops excitedly with a GPU device in paw

Through gRPC sockets, new clients leap and bound,
Informers cache the GPUs all around,
With Kubernetes patterns, the code is sound,
A code-gen dance makes types grow profound,
Watch streams shimmer as state wheels round! 🎡

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 52.03% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add Go SDK for GPUs' is clear, concise, and directly summarizes the primary change: introducing a new Go SDK for GPU resources, which is the main objective of this PR.

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

✨ Finishing touches
  • 📝 Generate docstrings

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.

Copy link
Contributor

@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: 17

🧹 Nitpick comments (35)
client-go/nvgrpc/client_conn_test.go (1)

34-34: Check connection Close() errors in cleanup.

The conn.Close() errors are currently ignored. While unlikely to fail in tests, checking these errors follows best practices for resource cleanup.

🔎 Proposed fix
-		conn.Close()
+		if err := conn.Close(); err != nil {
+			t.Errorf("failed to close connection: %v", err)
+		}

Also applies to: 47-47

client-go/DEVELOPMENT.md (1)

10-11: Optional markdown formatting improvements.

Static analysis identified minor markdown style issues:

  • Lines 10-11: List items could use 2-space indentation instead of 4
  • Line 77: "inside of" could be simplified to "inside"

These are purely stylistic and don't affect readability or functionality.

🔎 Optional markdown fixes
 * **yq**: Required to parse version configuration.
-    * *macOS*: `brew install yq`
-    * *Linux*: See [yq installation](https://github.com/mikefarah/yq)
+  * *macOS*: `brew install yq`
+  * *Linux*: See [yq installation](https://github.com/mikefarah/yq)
-The directory structure inside of `hack/overlays/` **must exactly mirror** the structure of the generated code.
+The directory structure inside `hack/overlays/` **must exactly mirror** the structure of the generated code.

Also applies to: 77-77

client-go/examples/streaming-daemon/main.go (2)

15-15: Missing package-level godoc comment.

As per coding guidelines, package-level godoc is required for all Go packages. Consider adding a doc comment describing the purpose of this example.

+// Package main demonstrates a streaming daemon that watches GPU resources
+// using the NVIDIA Device API client SDK with custom gRPC interceptors.
 package main

37-39: Consider using log/slog for structured logging.

The coding guidelines specify using log/slog for structured logging in Go code. While stdr provides structured logging via the logr interface, consider aligning with the project's logging standard for consistency.

api/proto/device/v1alpha1/gpu.proto (1)

27-51: Inconsistent indentation in comments.

Lines 35-37 and 47-49 use tab indentation while other comment lines use spaces. This creates visual inconsistency in the proto file.

   // resource_version represents the internal version of this object.
   //
   // Value must be treated as opaque by clients and passed unmodified back to the server.
-	// Populated by the system.
-	// Read-only.
-	// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
+  // Populated by the system.
+  // Read-only.
+  // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
   string resource_version = 2;
client-go/examples/fake-server/main.go (2)

15-15: Missing package-level godoc comment.

As per coding guidelines, package-level godoc is required for all Go packages.

+// Package main provides a fake NVIDIA Device API server for testing
+// the client SDK examples without requiring physical GPU hardware.
 package main

138-148: Consider adding a defensive check for conditions slice.

Direct access to Conditions[0] assumes the slice is non-empty. While the current initialization guarantees this, a defensive check would prevent potential panics if the initialization logic changes.

Suggested defensive check
+		if len(gpu.Status.Conditions) == 0 {
+			s.mu.Unlock()
+			continue
+		}
+
 		// Toggle the Ready condition
 		isReady := gpu.Status.Conditions[0].Status == metav1.ConditionTrue
client-go/examples/fake-server/README.md (1)

15-18: Consider documenting the NVIDIA_DEVICE_API_TARGET environment variable.

The implementation supports customizing the socket path via NVIDIA_DEVICE_API_TARGET, but this isn't mentioned in the README. This would help users who need to use a different socket location.

Suggested addition
 ## Behavior
 - **Endpoint**: Defaults to `unix:///tmp/nvidia-device-api.sock`
+  - Override with the `NVIDIA_DEVICE_API_TARGET` environment variable
 - **Inventory**: Simulates 8 NVIDIA GPUs (`gpu-0` through `gpu-7`)
client-go/Makefile (1)

187-187: Declare tools target as PHONY.

The tools target has no corresponding file output and should be declared PHONY to ensure it always runs when invoked. Based on static analysis hint.

🔎 Proposed fix
+.PHONY: tools
 tools: $(CLIENT_GEN) $(LISTER_GEN) $(INFORMER_GEN)
client-go/version/version_test.go (1)

9-19: Refactor to use testify assertions and improve test naming.

Per coding guidelines:

  1. Use testify/assert or testify/require for assertions instead of raw t.Errorf
  2. Test name should follow the format: TestFunctionName_Scenario_ExpectedBehavior
🔎 Proposed refactor using testify
+import (
+	"github.com/stretchr/testify/assert"
+)
+
-func TestUserAgent(t *testing.T) {
+func TestUserAgent_WithCustomVersion_ReturnsFormattedString(t *testing.T) {
 	originalVersion := GitVersion
 	defer func() { GitVersion = originalVersion }()
 
 	GitVersion = "v1.2.3-test"
 
 	expected := fmt.Sprintf("nvidia-device-api-client/v1.2.3-test (%s/%s)", runtime.GOOS, runtime.GOARCH)
-	if got := UserAgent(); got != expected {
-		t.Errorf("UserAgent() = %q, want %q", got, expected)
-	}
+	assert.Equal(t, expected, UserAgent())
 }

Based on coding guidelines: Use testify/assert and testify/require for assertions in Go tests, and name Go tests descriptively using format: TestFunctionName_Scenario_ExpectedBehavior.

client-go/examples/README.md (1)

17-23: Clarify the working directory for running the fake server.

The instructions show go run ./fake-server/main.go but don't specify which directory to execute this from. Based on the directory structure (lines 34-38), it appears the command should be run from the examples/ directory, but this isn't explicit.

🔎 Proposed clarification
 ### 1. Start the Fake Server
-The server creates a Unix domain socket (UDS) at `/tmp/nvidia-device-api.sock` and simulates a node with 8 GPUs. It also generates random status change events to test `Watch` and Informer capabilities.
+The server creates a Unix domain socket (UDS) at `/tmp/nvidia-device-api.sock` and simulates a node with 8 GPUs. It also generates random status change events to test `Watch` and Informer capabilities. Run from the `examples/` directory:
 
 ```bash
 # Run this in a separate terminal
+cd examples
 go run ./fake-server/main.go

</details>

</blockquote></details>
<details>
<summary>client-go/nvgrpc/options_test.go (1)</summary><blockquote>

`25-65`: **Refactor to use testify assertions per coding guidelines.**

The test uses raw `t.Errorf` calls instead of `testify/assert` or `testify/require` as specified in the coding guidelines. Consider refactoring for consistency with project standards.



<details>
<summary>🔎 Proposed refactor</summary>

```diff
 import (
 	"context"
 	"testing"
 
 	"github.com/go-logr/logr"
+	"github.com/stretchr/testify/assert"
 	"google.golang.org/grpc"
 )
 
 func TestDialOptions(t *testing.T) {
 	testLogger := logr.Discard()
 
 	dummyUnary := func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
 		return invoker(ctx, method, req, reply, cc, opts...)
 	}
 	dummyStream := func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
 		return streamer(ctx, desc, cc, method, opts...)
 	}
 
 	opts := []DialOption{
 		WithLogger(testLogger),
 		WithUnaryInterceptor(dummyUnary),
 		WithStreamInterceptor(dummyStream),
 		WithUnaryInterceptor(dummyUnary), // Test multiple appends
 		WithStreamInterceptor(dummyStream),
 	}
 
 	dOpts := &dialOptions{}
 	for _, opt := range opts {
 		opt(dOpts)
 	}
 
 	t.Run("Logger is correctly assigned", func(t *testing.T) {
-		if dOpts.logger != testLogger {
-			t.Errorf("expected logger to be set, got %v", dOpts.logger)
-		}
+		assert.Equal(t, testLogger, dOpts.logger, "logger should be correctly assigned")
 	})
 
 	t.Run("Unary interceptors are correctly appended", func(t *testing.T) {
-		if len(dOpts.unaryInterceptors) != 2 {
-			t.Errorf("expected 2 unary interceptors, got %d", len(dOpts.unaryInterceptors))
-		}
+		assert.Len(t, dOpts.unaryInterceptors, 2, "should have 2 unary interceptors")
 	})
 
 	t.Run("Stream interceptors are correctly appended", func(t *testing.T) {
-		if len(dOpts.streamInterceptors) != 2 {
-			t.Errorf("expected 2 stream interceptors, got %d", len(dOpts.streamInterceptors))
-		}
+		assert.Len(t, dOpts.streamInterceptors, 2, "should have 2 stream interceptors")
 	})
 }

Based on coding guidelines: Use testify/assert and testify/require for assertions in Go tests.

client-go/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1)

37-40: Simplify the nil return in generated overlay.

The explicit var ret *grpc.ClientConn followed by return ret is unnecessarily verbose. Since this is part of the gRPC overlay (as indicated in line 15), consider simplifying to return nil directly, which is clearer and more idiomatic.

🔎 Proposed simplification
 func (c *FakeDeviceV1alpha1) ClientConn() grpc.ClientConnInterface {
-	var ret *grpc.ClientConn
-	return ret
+	return nil
 }
client-go/nvgrpc/config_test.go (1)

54-56: Consider using testify/assert for cleaner assertions.

The tests use standard library error reporting (t.Errorf, t.Error) instead of testify assertions. Per coding guidelines, testify/assert and testify/require are preferred for more readable test assertions and better failure messages.

Example refactor using testify
+import (
+	"github.com/stretchr/testify/assert"
+)

 func TestConfig_Default_TargetPrecedence(t *testing.T) {
 	// ... test setup ...
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			t.Setenv(NvidiaDeviceAPITargetEnvVar, tt.envTarget)
 			cfg := &Config{Target: tt.argTarget}
 			cfg.Default()
-			if cfg.Target != tt.wantTarget {
-				t.Errorf("Target = %q, want %q", cfg.Target, tt.wantTarget)
-			}
+			assert.Equal(t, tt.wantTarget, cfg.Target)
 		})
 	}
 }

As per coding guidelines, using testify improves test readability and provides better assertion failure output.

Also applies to: 66-68, 76-78, 114-117

client-go/examples/basic-client/main.go (2)

39-45: Consider adding cleanup for the gRPC connection.

The example creates a clientset over a gRPC connection but does not close it. For a complete example, consider adding deferred cleanup if the clientset or underlying connection supports it.

🔎 Possible approach if a Close method exists
clientset, err := versioned.NewForConfig(config)
if err != nil {
	logger.Error(err, "unable to create clientset")
	os.Exit(1)
}
// If clientset has a Close method:
// defer clientset.Close()

47-64: Consider using context with timeout for production use.

The example uses context.Background() for API calls, which is fine for a demo but lacks timeout protection. For production code, consider using context.WithTimeout to prevent hanging on slow or unresponsive connections.

client-go/nvgrpc/interceptors.go (1)

15-15: Missing package-level godoc.

As per coding guidelines, package-level godoc is required for all Go packages. Consider adding a package comment describing the purpose of the nvgrpc package.

Suggested package documentation
 package nvgrpc
+
+// Package nvgrpc provides gRPC client utilities including interceptors,
+// configuration, and connection management for the NVIDIA Device API.

Note: If this documentation already exists in a doc.go file in the same package, this comment can be disregarded.

client-go/hack/overlays/client/versioned/integration_test.go (2)

279-287: Consider using gRPC status codes for more realistic mock behavior.

The mock returns a plain error for "not found" cases. For more realistic behavior matching gRPC semantics, consider returning a proper gRPC status error.

Suggested improvement
+import "google.golang.org/grpc/status"
+import "google.golang.org/grpc/codes"

 func (m *mockGpuServer) GetGpu(ctx context.Context, req *pb.GetGpuRequest) (*pb.GetGpuResponse, error) {
 	m.mu.RLock()
 	defer m.mu.RUnlock()
 	gpu, ok := m.gpus[req.Name]
 	if !ok {
-		return nil, fmt.Errorf("%s not found", req.Name)
+		return nil, status.Errorf(codes.NotFound, "%s not found", req.Name)
 	}
 	return &pb.GetGpuResponse{Gpu: gpu}, nil
 }

50-55: Consider migrating from deprecated grpc.DialContext to grpc.NewClient with bufconn support.

gRPC v1.63.0 introduced a new NewClient method to create a new ClientConn, and DialContext is marked as deprecated. For bufconn-based testing, the migration requires using the "passthrough" resolver scheme. Use one of these approaches:

  • Specify the "passthrough" resolver in the target string, e.g. "passthrough:target"
  • Or call resolver.SetDefaultScheme("passthrough") during initialization time (in an init() function), noting it is not thread-safe
client-go/examples/controller-shim/main.go (1)

15-15: Missing package-level godoc comment.

Per coding guidelines, all Go packages require package-level documentation explaining the purpose of this example.

Suggested fix
+// Package main provides an example controller-shim that demonstrates
+// wiring a gRPC-backed clientset into a controller-runtime manager,
+// enabling GPU resource reconciliation without a real Kubernetes API server.
 package main
client-go/nvgrpc/options.go (1)

15-15: Missing package-level godoc comment.

Per coding guidelines, all Go packages require documentation.

Suggested fix
+// Package nvgrpc provides gRPC client configuration and connection utilities
+// for the NVIDIA Device API, including dial options, interceptors, and logging.
 package nvgrpc
client-go/client/versioned/integration_test.go (2)

226-230: Goroutine error not reliably captured in test.

The t.Errorf inside the goroutine may execute after the test completes, causing the error to be missed or to panic. Consider using a channel or errgroup to properly capture and check for errors.

Suggested approach
+	cacheErrCh := make(chan error, 1)
 	go func() {
 		if err := c.Start(ctx); err != nil {
-			t.Errorf("Cache failed to start: %v", err)
+			cacheErrCh <- err
 		}
+		close(cacheErrCh)
 	}()
+	// Check for immediate startup errors
+	select {
+	case err := <-cacheErrCh:
+		if err != nil {
+			t.Fatalf("Cache failed to start: %v", err)
+		}
+	case <-time.After(100 * time.Millisecond):
+		// Cache started successfully
+	}

295-302: Mock server should return gRPC status errors.

Returning a plain fmt.Errorf doesn't translate to proper gRPC status codes. The client may not correctly interpret this as a NotFound error. Use status.Error for proper gRPC semantics.

Suggested fix
+import "google.golang.org/grpc/codes"
+import "google.golang.org/grpc/status"

 func (m *mockGpuServer) GetGpu(ctx context.Context, req *pb.GetGpuRequest) (*pb.GetGpuResponse, error) {
 	m.mu.RLock()
 	defer m.mu.RUnlock()
 	gpu, ok := m.gpus[req.Name]
 	if !ok {
-		return nil, fmt.Errorf("%s not found", req.Name)
+		return nil, status.Errorf(codes.NotFound, "%s not found", req.Name)
 	}
 	return &pb.GetGpuResponse{Gpu: gpu}, nil
 }
client-go/nvgrpc/watcher_test.go (3)

15-15: Missing package-level godoc.

As per coding guidelines, package-level godoc is required for all Go packages. Consider adding a brief description of the test package purpose.

+// Package nvgrpc provides tests for the nvgrpc watcher implementation.
 package nvgrpc

153-160: Consider removing time.Sleep to reduce test flakiness.

Using time.Sleep(10 * time.Millisecond) to "allow the receive loop to start" is fragile and can cause intermittent failures under load. Consider using synchronization primitives or restructuring to avoid timing dependencies.

🔎 Suggested approach

One approach is to have NewWatcher signal when the receive goroutine has started, or use a channel-based synchronization in the test helper:

 func TestWatcher_Stop(t *testing.T) {
 	ctx, cancel := context.WithCancel(context.Background())
 	source := NewFakeSource()
 
 	w := NewWatcher(source, cancel, logr.Discard())
-	// Allow the receive loop to start
-	time.Sleep(10 * time.Millisecond)
+	// Send a dummy event to ensure receive loop is running
+	source.events <- testEvent{"ADDED", &FakeObject{Name: "sync"}}
+	<-w.ResultChan() // Drain the sync event
 	w.Stop()

49-57: Consider using testify for assertions per coding guidelines.

The coding guidelines specify using testify/assert and testify/require for assertions. While the current assertions are functionally correct, using testify would improve consistency and provide better failure messages.

🔎 Example refactor
+import (
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)
+
 // In TestWatcher_NormalEvents:
-	wantTypes := []watch.EventType{watch.Added, watch.Modified, watch.Deleted}
-	if len(got) != len(wantTypes) {
-		t.Fatalf("got %d events, want %d", len(got), len(wantTypes))
-	}
-	for i, ev := range got {
-		if ev.Type != wantTypes[i] {
-			t.Errorf("event %d: got type %v, want %v", i, ev.Type, wantTypes[i])
-		}
-	}
+	wantTypes := []watch.EventType{watch.Added, watch.Modified, watch.Deleted}
+	require.Len(t, got, len(wantTypes))
+	for i, ev := range got {
+		assert.Equal(t, wantTypes[i], ev.Type, "event %d", i)
+	}
client-go/hack/overlays/client/versioned/clientset.go (1)

1-1: Missing package-level godoc.

As per coding guidelines, package-level godoc is required. Consider adding documentation describing the purpose of this versioned clientset package.

+// Package versioned provides a typed client for the NVIDIA Device API,
+// exposing Kubernetes-style accessors over a gRPC connection.
 package versioned
client-go/nvgrpc/config.go (1)

15-15: Missing package-level godoc.

As per coding guidelines, package-level godoc is required for all Go packages.

+// Package nvgrpc provides configuration and utilities for connecting to the
+// NVIDIA Device API via gRPC, including connection setup, interceptors, and
+// watch stream handling.
 package nvgrpc
client-go/client/versioned/typed/device/v1alpha1/gpu.go (1)

15-17: Package-level godoc is missing.

As per coding guidelines, package-level godoc is required for all Go packages. Consider adding a package comment describing the purpose of this v1alpha1 client package.

+// Package v1alpha1 contains the typed client for the device.nvidia.com/v1alpha1 API group.
 package v1alpha1
client-go/client/versioned/clientset.go (1)

48-60: Redundant shallow copy when calling NewForConfigAndClient.

Line 53 creates a shallow copy, but NewForConfigAndClient (line 72) creates another shallow copy. Since you're already passing the address of configShallowCopy, the second copy is unnecessary overhead.

🔎 Suggested simplification in NewForConfigAndClient

Either remove the shallow copy from NewForConfigAndClient since callers are expected to pass already-copied configs, or document that NewForConfigAndClient takes ownership and copies internally. For consistency with the parent Clientset.NewForConfig, you might keep it for safety when called directly.

client-go/client/versioned/typed/device/v1alpha1/device_client.go (2)

53-60: NewForConfigAndClient returns an error but never fails.

The function signature returns error, but the implementation always returns nil. This is consistent with the Kubernetes pattern for future extensibility, but consider adding a comment explaining this is for API compatibility.


73-79: New() uses logr.Discard(), which silently drops all logs.

When using New(conn) directly, all logging is discarded. Consider documenting this behavior or providing a NewWithLogger variant for users who want observability without full config setup.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1)

1-7: Missing license header and generated-code disclaimer.

Other files in this PR include the Apache 2.0 license header and "DO NOT EDIT" comment. This overlay file is missing both, which is inconsistent with the rest of the codebase.

🔎 Add license header
+//  Copyright (c) 2025, NVIDIA CORPORATION.  All rights reserved.
+// 
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at
+// 
+//      http://www.apache.org/licenses/LICENSE-2.0
+// 
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+
 package v1alpha1
client-go/nvgrpc/watcher.go (1)

15-15: Package-level godoc is missing.

As per coding guidelines, package-level godoc is required. Consider adding documentation describing the nvgrpc package's purpose.

client-go/informers/externalversions/factory.go (1)

169-173: Minor typo in variable name.

The variable informType should be informerType for consistency with the rest of the codebase. However, since this is generated code (line 15), this should be fixed in the generator template rather than here.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ef820c3 and f4e8d48.

⛔ Files ignored due to path filters (3)
  • api/gen/go/device/v1alpha1/gpu.pb.go is excluded by !**/*.pb.go, !**/gen/**
  • api/go.sum is excluded by !**/*.sum
  • client-go/go.sum is excluded by !**/*.sum
📒 Files selected for processing (71)
  • .gitignore (1 hunks)
  • .versions.yaml (1 hunks)
  • api/Makefile (5 hunks)
  • api/device/v1alpha1/converter.go (1 hunks)
  • api/device/v1alpha1/doc.go (1 hunks)
  • api/device/v1alpha1/gpu_conversion.go (1 hunks)
  • api/device/v1alpha1/gpu_conversion_test.go (1 hunks)
  • api/device/v1alpha1/gpu_types.go (1 hunks)
  • api/device/v1alpha1/register.go (1 hunks)
  • api/device/v1alpha1/zz_generated.conversion.go (1 hunks)
  • api/device/v1alpha1/zz_generated.deepcopy.go (1 hunks)
  • api/go.mod (1 hunks)
  • api/hack/boilerplate.go.txt (1 hunks)
  • api/proto/device/v1alpha1/gpu.proto (4 hunks)
  • client-go/DEVELOPMENT.md (1 hunks)
  • client-go/Makefile (1 hunks)
  • client-go/README.md (1 hunks)
  • client-go/client/versioned/clientset.go (1 hunks)
  • client-go/client/versioned/fake/clientset_generated.go (1 hunks)
  • client-go/client/versioned/fake/doc.go (1 hunks)
  • client-go/client/versioned/fake/register.go (1 hunks)
  • client-go/client/versioned/integration_test.go (1 hunks)
  • client-go/client/versioned/scheme/doc.go (1 hunks)
  • client-go/client/versioned/scheme/register.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/device_client.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/doc.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/fake/doc.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_gpu.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/generated_expansion.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/gpu.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1 hunks)
  • client-go/examples/README.md (1 hunks)
  • client-go/examples/basic-client/README.md (1 hunks)
  • client-go/examples/basic-client/main.go (1 hunks)
  • client-go/examples/controller-shim/README.md (1 hunks)
  • client-go/examples/controller-shim/main.go (1 hunks)
  • client-go/examples/fake-server/README.md (1 hunks)
  • client-go/examples/fake-server/main.go (1 hunks)
  • client-go/examples/streaming-daemon/README.md (1 hunks)
  • client-go/examples/streaming-daemon/main.go (1 hunks)
  • client-go/go.mod (1 hunks)
  • client-go/hack/apply-overlays.sh (1 hunks)
  • client-go/hack/boilerplate.go.txt (1 hunks)
  • client-go/hack/boilerplate_overlay.go.txt (1 hunks)
  • client-go/hack/overlays/client/versioned/clientset.go (1 hunks)
  • client-go/hack/overlays/client/versioned/integration_test.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1 hunks)
  • client-go/informers/externalversions/device/interface.go (1 hunks)
  • client-go/informers/externalversions/device/v1alpha1/gpu.go (1 hunks)
  • client-go/informers/externalversions/device/v1alpha1/interface.go (1 hunks)
  • client-go/informers/externalversions/factory.go (1 hunks)
  • client-go/informers/externalversions/generic.go (1 hunks)
  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go (1 hunks)
  • client-go/listers/device/v1alpha1/expansion_generated.go (1 hunks)
  • client-go/listers/device/v1alpha1/gpu.go (1 hunks)
  • client-go/nvgrpc/client_conn.go (1 hunks)
  • client-go/nvgrpc/client_conn_test.go (1 hunks)
  • client-go/nvgrpc/config.go (1 hunks)
  • client-go/nvgrpc/config_test.go (1 hunks)
  • client-go/nvgrpc/interceptors.go (1 hunks)
  • client-go/nvgrpc/interceptors_test.go (1 hunks)
  • client-go/nvgrpc/options.go (1 hunks)
  • client-go/nvgrpc/options_test.go (1 hunks)
  • client-go/nvgrpc/watcher.go (1 hunks)
  • client-go/nvgrpc/watcher_test.go (1 hunks)
  • client-go/version/version.go (1 hunks)
  • client-go/version/version_test.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.go: Follow standard Go conventions with gofmt and golint
Use structured logging via log/slog in Go code
Wrap errors with context using fmt.Errorf("context: %w", err) in Go code
Within retry.RetryOnConflict blocks, return errors without wrapping to preserve retry behavior
Use meaningful variable names such as synced over ok for cache sync checks
Use client-go for Kubernetes API interactions in Go code
Prefer informers over direct API calls for watching Kubernetes resources
Implement proper shutdown handling with context cancellation in Go code
Package-level godoc required for all Go packages
Function comments required for all exported Go functions
Use inline comments for complex logic only in Go code
TODO comments should reference issues in Go code
Extract informer event handler setup into helper methods
Use separate informers for different Kubernetes resource types

Files:

  • client-go/client/versioned/typed/device/v1alpha1/generated_expansion.go
  • client-go/listers/device/v1alpha1/expansion_generated.go
  • api/device/v1alpha1/doc.go
  • client-go/nvgrpc/interceptors_test.go
  • api/device/v1alpha1/gpu_conversion_test.go
  • client-go/version/version_test.go
  • client-go/client/versioned/fake/doc.go
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go
  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go
  • api/device/v1alpha1/register.go
  • client-go/nvgrpc/client_conn_test.go
  • client-go/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/nvgrpc/interceptors.go
  • client-go/nvgrpc/watcher_test.go
  • client-go/nvgrpc/client_conn.go
  • client-go/client/versioned/typed/device/v1alpha1/fake/doc.go
  • client-go/nvgrpc/options.go
  • client-go/client/versioned/scheme/register.go
  • api/device/v1alpha1/gpu_types.go
  • client-go/client/versioned/integration_test.go
  • client-go/listers/device/v1alpha1/gpu.go
  • client-go/version/version.go
  • api/device/v1alpha1/gpu_conversion.go
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_gpu.go
  • client-go/informers/externalversions/device/interface.go
  • client-go/client/versioned/typed/device/v1alpha1/gpu.go
  • client-go/nvgrpc/config.go
  • client-go/informers/externalversions/device/v1alpha1/interface.go
  • client-go/examples/basic-client/main.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go
  • api/device/v1alpha1/converter.go
  • client-go/informers/externalversions/generic.go
  • client-go/examples/controller-shim/main.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • api/device/v1alpha1/zz_generated.deepcopy.go
  • client-go/nvgrpc/options_test.go
  • client-go/hack/overlays/client/versioned/clientset.go
  • client-go/client/versioned/typed/device/v1alpha1/doc.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/nvgrpc/watcher.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/informers/externalversions/device/v1alpha1/gpu.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go
  • client-go/client/versioned/clientset.go
  • client-go/examples/streaming-daemon/main.go
  • client-go/client/versioned/scheme/doc.go
  • client-go/examples/fake-server/main.go
  • client-go/client/versioned/fake/register.go
  • client-go/nvgrpc/config_test.go
  • api/device/v1alpha1/zz_generated.conversion.go
  • client-go/informers/externalversions/factory.go
  • client-go/client/versioned/fake/clientset_generated.go
**/*_test.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*_test.go: Use envtest for testing Kubernetes controllers instead of fake clients
Use testify/assert and testify/require for assertions in Go tests
Write table-driven tests when testing multiple scenarios in Go
Name Go tests descriptively using format: TestFunctionName_Scenario_ExpectedBehavior

Files:

  • client-go/nvgrpc/interceptors_test.go
  • api/device/v1alpha1/gpu_conversion_test.go
  • client-go/version/version_test.go
  • client-go/nvgrpc/client_conn_test.go
  • client-go/nvgrpc/watcher_test.go
  • client-go/client/versioned/integration_test.go
  • client-go/nvgrpc/options_test.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/nvgrpc/config_test.go
**/go.mod

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use go.mod for each service as a separate Go module with semantic import versioning

Files:

  • api/go.mod
  • client-go/go.mod
🧠 Learnings (13)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code

Applied to files:

  • client-go/hack/boilerplate_overlay.go.txt
  • client-go/examples/basic-client/README.md
  • client-go/examples/README.md
  • client-go/client/versioned/fake/doc.go
  • .versions.yaml
  • client-go/hack/apply-overlays.sh
  • client-go/nvgrpc/client_conn.go
  • client-go/client/versioned/scheme/register.go
  • client-go/README.md
  • client-go/client/versioned/typed/device/v1alpha1/gpu.go
  • client-go/examples/basic-client/main.go
  • api/go.mod
  • client-go/hack/overlays/client/versioned/clientset.go
  • client-go/client/versioned/typed/device/v1alpha1/doc.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/nvgrpc/watcher.go
  • .gitignore
  • client-go/client/versioned/scheme/doc.go
  • client-go/DEVELOPMENT.md
  • client-go/go.mod
  • client-go/Makefile
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: All files must include Apache 2.0 license header

Applied to files:

  • client-go/hack/boilerplate.go.txt
  • api/hack/boilerplate.go.txt
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Use `envtest` for testing Kubernetes controllers instead of fake clients

Applied to files:

  • client-go/examples/README.md
  • client-go/version/version_test.go
  • client-go/client/versioned/fake/doc.go
  • .versions.yaml
  • client-go/client/versioned/typed/device/v1alpha1/fake/doc.go
  • client-go/client/versioned/integration_test.go
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_gpu.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • .gitignore
  • client-go/go.mod
  • client-go/client/versioned/fake/clientset_generated.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Package-level godoc required for all Go packages

Applied to files:

  • client-go/client/versioned/fake/doc.go
  • client-go/client/versioned/typed/device/v1alpha1/doc.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Keep Go dependencies minimal and up-to-date

Applied to files:

  • .versions.yaml
  • api/go.mod
  • client-go/go.mod
  • api/Makefile
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Function comments required for all exported Go functions

Applied to files:

  • api/hack/boilerplate.go.txt
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Extract informer event handler setup into helper methods

Applied to files:

  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go
  • client-go/informers/externalversions/generic.go
  • client-go/informers/externalversions/factory.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use separate informers for different Kubernetes resource types

Applied to files:

  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go
  • client-go/informers/externalversions/generic.go
  • client-go/informers/externalversions/device/v1alpha1/gpu.go
  • client-go/informers/externalversions/factory.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Prefer informers over direct API calls for watching Kubernetes resources

Applied to files:

  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go
  • client-go/informers/externalversions/generic.go
  • client-go/nvgrpc/watcher.go
  • client-go/informers/externalversions/device/v1alpha1/gpu.go
  • client-go/go.mod
  • client-go/informers/externalversions/factory.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/go.mod : Use `go.mod` for each service as a separate Go module with semantic import versioning

Applied to files:

  • api/go.mod
  • client-go/go.mod
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Follow standard Go conventions with gofmt and golint

Applied to files:

  • .gitignore
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to data-models/protobufs/**/*.proto : Use semantic versioning for breaking changes in Protocol Buffer messages

Applied to files:

  • api/Makefile
🧬 Code graph analysis (29)
client-go/nvgrpc/interceptors_test.go (1)
client-go/nvgrpc/interceptors.go (2)
  • NewLatencyUnaryInterceptor (28-59)
  • NewLatencyStreamInterceptor (62-92)
api/device/v1alpha1/gpu_conversion_test.go (2)
api/device/v1alpha1/gpu_conversion.go (4)
  • FromProto (25-32)
  • ToProto (35-40)
  • FromProtoList (43-48)
  • ToProtoList (51-56)
api/gen/go/device/v1alpha1/gpu.pb.go (21)
  • Gpu (159-169)
  • Gpu (182-182)
  • Gpu (197-199)
  • ObjectMeta (40-53)
  • ObjectMeta (66-66)
  • ObjectMeta (81-83)
  • GpuSpec (277-285)
  • GpuSpec (298-298)
  • GpuSpec (313-315)
  • GpuStatus (325-333)
  • GpuStatus (346-346)
  • GpuStatus (361-363)
  • Condition (380-398)
  • Condition (411-411)
  • Condition (426-428)
  • GpuList (223-230)
  • GpuList (243-243)
  • GpuList (258-260)
  • ListMeta (100-112)
  • ListMeta (125-125)
  • ListMeta (140-142)
client-go/version/version_test.go (1)
client-go/version/version.go (2)
  • GitVersion (25-25)
  • UserAgent (28-35)
client-go/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1)
client-go/client/versioned/typed/device/v1alpha1/gpu.go (1)
  • GPUInterface (38-43)
client-go/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (2)
api/gen/go/device/v1alpha1/gpu_grpc.pb.go (1)
  • GpuService_WatchGpusClient (100-100)
api/device/v1alpha1/gpu_conversion.go (1)
  • FromProto (25-32)
client-go/informers/externalversions/internalinterfaces/factory_interfaces.go (4)
client-go/client/versioned/clientset.go (1)
  • Interface (28-30)
client-go/hack/overlays/client/versioned/clientset.go (1)
  • Interface (12-14)
client-go/informers/externalversions/device/interface.go (1)
  • Interface (25-28)
client-go/informers/externalversions/device/v1alpha1/interface.go (1)
  • Interface (24-27)
api/device/v1alpha1/register.go (1)
api/device/v1alpha1/gpu_types.go (2)
  • GPU (55-61)
  • GPUList (67-71)
client-go/nvgrpc/client_conn_test.go (4)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/nvgrpc/client_conn.go (1)
  • ClientConnFor (27-72)
client-go/version/version.go (1)
  • UserAgent (28-35)
client-go/nvgrpc/options.go (1)
  • WithLogger (32-36)
client-go/client/versioned/typed/device/v1alpha1/device_client.go (2)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/nvgrpc/client_conn.go (1)
  • ClientConnFor (27-72)
client-go/nvgrpc/watcher_test.go (1)
client-go/nvgrpc/watcher.go (1)
  • NewWatcher (47-62)
client-go/nvgrpc/client_conn.go (4)
client-go/nvgrpc/config.go (3)
  • Config (41-49)
  • DefaultKeepAliveTime (34-34)
  • DefaultKeepAliveTimeout (37-37)
client-go/nvgrpc/options.go (1)
  • DialOption (23-23)
client-go/version/version.go (1)
  • UserAgent (28-35)
client-go/nvgrpc/interceptors.go (2)
  • NewLatencyUnaryInterceptor (28-59)
  • NewLatencyStreamInterceptor (62-92)
api/device/v1alpha1/gpu_types.go (1)
api/gen/go/device/v1alpha1/gpu.pb.go (9)
  • Condition (380-398)
  • Condition (411-411)
  • Condition (426-428)
  • ObjectMeta (40-53)
  • ObjectMeta (66-66)
  • ObjectMeta (81-83)
  • ListMeta (100-112)
  • ListMeta (125-125)
  • ListMeta (140-142)
api/device/v1alpha1/gpu_conversion.go (4)
api/device/v1alpha1/converter.go (1)
  • Converter (30-104)
api/device/v1alpha1/zz_generated.conversion.go (1)
  • ConverterImpl (11-11)
api/gen/go/device/v1alpha1/gpu.pb.go (6)
  • Gpu (159-169)
  • Gpu (182-182)
  • Gpu (197-199)
  • GpuList (223-230)
  • GpuList (243-243)
  • GpuList (258-260)
api/device/v1alpha1/gpu_types.go (2)
  • GPU (55-61)
  • GPUList (67-71)
client-go/client/versioned/typed/device/v1alpha1/fake/fake_gpu.go (6)
api/device/v1alpha1/gpu_types.go (2)
  • GPU (55-61)
  • GPUList (67-71)
client-go/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1)
  • FakeDeviceV1alpha1 (25-27)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1)
  • FakeDeviceV1alpha1 (9-11)
client-go/client/versioned/typed/device/v1alpha1/gpu.go (1)
  • GPUInterface (38-43)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (1)
  • GPUInterface (22-27)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
client-go/informers/externalversions/device/interface.go (5)
client-go/informers/externalversions/device/v1alpha1/interface.go (2)
  • Interface (24-27)
  • New (36-38)
client-go/informers/externalversions/factory.go (1)
  • SharedInformerFactory (224-256)
client-go/informers/externalversions/internalinterfaces/factory_interfaces.go (2)
  • SharedInformerFactory (32-35)
  • TweakListOptionsFunc (38-38)
client-go/client/versioned/typed/device/v1alpha1/device_client.go (1)
  • New (74-79)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1)
  • New (58-63)
client-go/informers/externalversions/device/v1alpha1/interface.go (1)
client-go/informers/externalversions/device/v1alpha1/gpu.go (1)
  • GPUInformer (35-38)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (2)
api/gen/go/device/v1alpha1/gpu_grpc.pb.go (1)
  • GpuService_WatchGpusClient (100-100)
api/device/v1alpha1/gpu_conversion.go (1)
  • FromProto (25-32)
api/device/v1alpha1/converter.go (3)
api/gen/go/device/v1alpha1/gpu.pb.go (21)
  • Gpu (159-169)
  • Gpu (182-182)
  • Gpu (197-199)
  • GpuList (223-230)
  • GpuList (243-243)
  • GpuList (258-260)
  • ObjectMeta (40-53)
  • ObjectMeta (66-66)
  • ObjectMeta (81-83)
  • ListMeta (100-112)
  • ListMeta (125-125)
  • ListMeta (140-142)
  • GpuSpec (277-285)
  • GpuSpec (298-298)
  • GpuSpec (313-315)
  • GpuStatus (325-333)
  • GpuStatus (346-346)
  • GpuStatus (361-363)
  • Condition (380-398)
  • Condition (411-411)
  • Condition (426-428)
api/device/v1alpha1/gpu_types.go (4)
  • GPU (55-61)
  • GPUList (67-71)
  • GPUSpec (24-30)
  • GPUStatus (35-45)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
client-go/informers/externalversions/generic.go (1)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
api/device/v1alpha1/zz_generated.deepcopy.go (1)
api/device/v1alpha1/gpu_types.go (4)
  • GPU (55-61)
  • GPUList (67-71)
  • GPUSpec (24-30)
  • GPUStatus (35-45)
client-go/nvgrpc/options_test.go (1)
client-go/nvgrpc/options.go (4)
  • DialOption (23-23)
  • WithLogger (32-36)
  • WithUnaryInterceptor (39-43)
  • WithStreamInterceptor (46-50)
client-go/hack/overlays/client/versioned/clientset.go (3)
client-go/client/versioned/typed/device/v1alpha1/device_client.go (5)
  • DeviceV1alpha1Interface (25-28)
  • DeviceV1alpha1Client (31-34)
  • NewForConfig (43-51)
  • NewForConfigAndClient (55-60)
  • New (74-79)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/nvgrpc/client_conn.go (1)
  • ClientConnFor (27-72)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (2)
client-go/client/versioned/clientset.go (4)
  • NewForConfig (48-60)
  • NewForConfigAndClient (64-81)
  • NewForConfigOrDie (85-92)
  • New (95-99)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/hack/overlays/client/versioned/integration_test.go (3)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/client/versioned/clientset.go (2)
  • NewForConfigAndClient (64-81)
  • New (95-99)
api/gen/go/device/v1alpha1/gpu.pb.go (18)
  • WatchGpusResponse (696-713)
  • WatchGpusResponse (726-726)
  • WatchGpusResponse (741-743)
  • Gpu (159-169)
  • Gpu (182-182)
  • Gpu (197-199)
  • ObjectMeta (40-53)
  • ObjectMeta (66-66)
  • ObjectMeta (81-83)
  • GpuSpec (277-285)
  • GpuSpec (298-298)
  • GpuSpec (313-315)
  • GpuList (223-230)
  • GpuList (243-243)
  • GpuList (258-260)
  • WatchGpusRequest (650-656)
  • WatchGpusRequest (669-669)
  • WatchGpusRequest (684-686)
client-go/informers/externalversions/device/v1alpha1/gpu.go (6)
client-go/listers/device/v1alpha1/gpu.go (1)
  • GPULister (28-36)
client-go/informers/externalversions/internalinterfaces/factory_interfaces.go (2)
  • SharedInformerFactory (32-35)
  • TweakListOptionsFunc (38-38)
client-go/client/versioned/clientset.go (1)
  • Interface (28-30)
client-go/hack/overlays/client/versioned/clientset.go (1)
  • Interface (12-14)
client-go/informers/externalversions/device/v1alpha1/interface.go (1)
  • Interface (24-27)
api/device/v1alpha1/gpu_types.go (1)
  • GPU (55-61)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (3)
api/device/v1alpha1/gpu_types.go (2)
  • GPU (55-61)
  • GPUList (67-71)
api/gen/go/device/v1alpha1/gpu_grpc.pb.go (1)
  • GpuServiceClient (46-53)
api/gen/go/device/v1alpha1/gpu.pb.go (9)
  • GetGpuRequest (466-472)
  • GetGpuRequest (485-485)
  • GetGpuRequest (500-502)
  • ListGpusRequest (558-564)
  • ListGpusRequest (577-577)
  • ListGpusRequest (592-594)
  • WatchGpusRequest (650-656)
  • WatchGpusRequest (669-669)
  • WatchGpusRequest (684-686)
client-go/examples/fake-server/main.go (3)
api/device/v1alpha1/gpu_types.go (3)
  • GPU (55-61)
  • GPUSpec (24-30)
  • GPUStatus (35-45)
api/gen/go/device/v1alpha1/gpu.pb.go (9)
  • ObjectMeta (40-53)
  • ObjectMeta (66-66)
  • ObjectMeta (81-83)
  • Gpu (159-169)
  • Gpu (182-182)
  • Gpu (197-199)
  • WatchGpusResponse (696-713)
  • WatchGpusResponse (726-726)
  • WatchGpusResponse (741-743)
api/device/v1alpha1/gpu_conversion.go (1)
  • ToProto (35-40)
client-go/nvgrpc/config_test.go (2)
client-go/nvgrpc/config.go (3)
  • DefaultNvidiaDeviceAPISocket (31-31)
  • NvidiaDeviceAPITargetEnvVar (28-28)
  • Config (41-49)
client-go/version/version.go (1)
  • UserAgent (28-35)
api/device/v1alpha1/zz_generated.conversion.go (3)
api/gen/go/device/v1alpha1/gpu.pb.go (21)
  • Gpu (159-169)
  • Gpu (182-182)
  • Gpu (197-199)
  • ObjectMeta (40-53)
  • ObjectMeta (66-66)
  • ObjectMeta (81-83)
  • Condition (380-398)
  • Condition (411-411)
  • Condition (426-428)
  • GpuList (223-230)
  • GpuList (243-243)
  • GpuList (258-260)
  • ListMeta (100-112)
  • ListMeta (125-125)
  • ListMeta (140-142)
  • GpuSpec (277-285)
  • GpuSpec (298-298)
  • GpuSpec (313-315)
  • GpuStatus (325-333)
  • GpuStatus (346-346)
  • GpuStatus (361-363)
api/device/v1alpha1/gpu_types.go (4)
  • GPU (55-61)
  • GPUList (67-71)
  • GPUSpec (24-30)
  • GPUStatus (35-45)
api/device/v1alpha1/converter.go (4)
  • FromProtobufTypeMeta (107-112)
  • FromProtobufTimestamp (123-128)
  • FromProtobufListTypeMeta (115-120)
  • ToProtobufTimestamp (131-133)
🪛 checkmake (0.2.2)
client-go/Makefile

[warning] 187-187: Target "tools" should be declared PHONY.

(phonydeclared)

🪛 LanguageTool
client-go/DEVELOPMENT.md

[style] ~77-~77: This phrase is redundant. Consider using “inside”.
Context: ... informers/) The directory structure inside of hack/overlays/ *must exactly mirror...

(OUTSIDE_OF)

🪛 markdownlint-cli2 (0.18.1)
client-go/DEVELOPMENT.md

10-10: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


11-11: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)

Copy link
Contributor

@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: 4

♻️ Duplicate comments (7)
client-go/hack/overlays/client/versioned/integration_test.go (1)

210-214: Avoid calling t.Errorf from a goroutine.

This issue was already flagged in a previous review. Calling t.Errorf from a goroutine is unsafe and can cause race conditions. Consider using an error channel pattern as suggested previously.

client-go/nvgrpc/watcher.go (1)

64-77: Race condition in Stop() with double-close protection.

This is a known issue already flagged in previous reviews. The select on lines 72-76 attempts to prevent double-close of w.done, but there's a race window between checking <-w.done and calling close(w.done). Additionally, receive() calls defer w.Stop() (line 90), which could race with an external Stop() call.

client-go/informers/externalversions/factory.go (1)

200-224: Documentation references non-existent method.

This is a known issue already flagged in previous reviews. The example documentation references factory.WaitForStop() on line 208, but the actual method is Shutdown(). Since this is generated code, the fix should be applied to the generator template.

client-go/client/versioned/fake/clientset_generated.go (1)

52-53: Typo in variable name: watchActcion should be watchAction.

This typo was already identified in a previous review.

client-go/examples/controller-shim/main.go (1)

58-62: The informer factory is never started.

This issue was already flagged in a previous review. The comment on line 60 is incorrect—controller-runtime only starts informers created through its own cache machinery, not externally injected ones.

api/Makefile (2)

124-131: Undefined variable API_PKGS_COMMA will cause build failure.

Line 128 references API_PKGS_COMMA, but only API_VERSIONS_COMMA (line 31) and API_PKGS (line 34) are defined. This will pass an empty string to --bounding-dirs.

🔎 Proposed fix: Add the missing variable definition

Add near line 35 after API_PKGS:

 # Helper for tools that need full package paths
 API_PKGS := $(foreach version,$(API_VERSIONS),$(MODULE_NAME)/$(version))
+
+# Helper for tools that need comma-separated package paths
+API_PKGS_COMMA := $(subst $(SPACE),$(COMMA),$(API_PKGS))

134-134: Minor typo: double period in help text.

🔎 Proposed fix
-conversion-gen: $(GOVERTER) clean-conversion ## Generate conversion code..
+conversion-gen: $(GOVERTER) clean-conversion ## Generate conversion code.
🧹 Nitpick comments (12)
client-go/DEVELOPMENT.md (2)

77-77: Optional: Simplify phrasing.

Static analysis suggests "inside" instead of "inside of" for more concise writing.

-The directory structure inside of `hack/overlays/` **must exactly mirror** the structure of the generated code.
+The directory structure inside `hack/overlays/` **must exactly mirror** the structure of the generated code.

10-11: Optional: Fix markdown list indentation.

The nested list items use 4-space indentation, but markdownlint expects 2 spaces for consistency.

 * **yq**: Required to parse version configuration.
-    * *macOS*: `brew install yq`
-    * *Linux*: See [yq installation](https://github.com/mikefarah/yq)
+  * *macOS*: `brew install yq`
+  * *Linux*: See [yq installation](https://github.com/mikefarah/yq)
client-go/hack/overlays/client/versioned/integration_test.go (2)

50-56: Consider using grpc.NewClient instead of deprecated grpc.DialContext.

grpc.DialContext is deprecated in gRPC v1.60+. For new code, grpc.NewClient is preferred. However, since this is test code and bufconn integration with NewClient can be trickier, this is a low-priority change.


279-287: Consider returning a gRPC status error for "not found" case.

Returning status.Errorf(codes.NotFound, "%s not found", req.Name) instead of fmt.Errorf would better simulate real gRPC server behavior, which could be important if tests need to verify error handling based on gRPC status codes.

Suggested fix
+import "google.golang.org/grpc/status"
+import "google.golang.org/grpc/codes"

 func (m *mockGpuServer) GetGpu(ctx context.Context, req *pb.GetGpuRequest) (*pb.GetGpuResponse, error) {
 	m.mu.RLock()
 	defer m.mu.RUnlock()
 	gpu, ok := m.gpus[req.Name]
 	if !ok {
-		return nil, fmt.Errorf("%s not found", req.Name)
+		return nil, status.Errorf(codes.NotFound, "%s not found", req.Name)
 	}
 	return &pb.GetGpuResponse{Gpu: gpu}, nil
 }
client-go/nvgrpc/config.go (1)

40-49: Consider documenting how to configure the logger.

The logger field is unexported, making it unclear how callers set a custom logger. If there's a WithLogger option (mentioned in related files like options.go), consider adding a brief comment here or in the package documentation pointing to that mechanism.

api/device/v1alpha1/gpu_types.go (1)

15-15: Missing package-level godoc comment.

As per coding guidelines, package-level godoc is required for all Go packages. Consider adding a package comment describing the v1alpha1 API types.

Suggested fix
+// Package v1alpha1 contains API types for the device.nvidia.com/v1alpha1 API group.
+// It defines GPU resources that represent physical GPU hardware on a node.
 package v1alpha1
client-go/examples/controller-shim/main.go (1)

15-15: Missing package-level godoc comment.

As per coding guidelines, package-level godoc is required. Consider adding a comment describing this example's purpose.

Suggested fix
+// Package main demonstrates integrating the NVIDIA Device API gRPC client
+// with controller-runtime by injecting a gRPC-backed informer into the Manager's cache.
 package main
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1)

1-7: Missing license header in overlay file.

Unlike the main device_client.go, this overlay file lacks the Apache 2.0 license header. Consider adding it for consistency across the codebase.

🔎 Proposed fix
+//  Copyright (c) 2025, NVIDIA CORPORATION.  All rights reserved.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+
 package v1alpha1
client-go/Makefile (1)

187-187: Target "tools" should be declared PHONY.

The tools target has no corresponding file and should be declared as .PHONY to ensure it always runs when invoked.

🔎 Proposed fix
+.PHONY: tools
 tools: $(CLIENT_GEN) $(LISTER_GEN) $(INFORMER_GEN)
api/device/v1alpha1/zz_generated.conversion.go (3)

1-4: Missing package documentation.

The coding guidelines require package-level godoc for all Go packages. Since this is generated code, consider updating the generator configuration to emit a package comment.


11-11: Missing type documentation.

The exported ConverterImpl type lacks a godoc comment. Since this is generated code, consider configuring the generator to emit documentation for exported types.


13-22: Conversion logic is correct.

The nil-safety and field mappings are properly implemented. The zero-value return for nil input is appropriate. However, the exported method lacks a godoc comment—consider configuring the generator to emit documentation.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f4e8d48 and 9b3add0.

⛔ Files ignored due to path filters (3)
  • api/gen/go/device/v1alpha1/gpu.pb.go is excluded by !**/*.pb.go, !**/gen/**
  • api/go.sum is excluded by !**/*.sum
  • client-go/go.sum is excluded by !**/*.sum
📒 Files selected for processing (73)
  • .gitignore (1 hunks)
  • .versions.yaml (1 hunks)
  • api/Makefile (5 hunks)
  • api/device/v1alpha1/converter.go (1 hunks)
  • api/device/v1alpha1/doc.go (1 hunks)
  • api/device/v1alpha1/gpu_conversion.go (1 hunks)
  • api/device/v1alpha1/gpu_conversion_test.go (1 hunks)
  • api/device/v1alpha1/gpu_types.go (1 hunks)
  • api/device/v1alpha1/register.go (1 hunks)
  • api/device/v1alpha1/zz_generated.conversion.go (1 hunks)
  • api/device/v1alpha1/zz_generated.deepcopy.go (1 hunks)
  • api/go.mod (1 hunks)
  • api/hack/boilerplate.go.txt (1 hunks)
  • api/proto/device/v1alpha1/gpu.proto (4 hunks)
  • client-go/DEVELOPMENT.md (1 hunks)
  • client-go/Makefile (1 hunks)
  • client-go/README.md (1 hunks)
  • client-go/client/versioned/clientset.go (1 hunks)
  • client-go/client/versioned/fake/clientset_generated.go (1 hunks)
  • client-go/client/versioned/fake/doc.go (1 hunks)
  • client-go/client/versioned/fake/register.go (1 hunks)
  • client-go/client/versioned/integration_test.go (1 hunks)
  • client-go/client/versioned/scheme/doc.go (1 hunks)
  • client-go/client/versioned/scheme/register.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/device_client.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/doc.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/fake/doc.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_gpu.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/generated_expansion.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/gpu.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1 hunks)
  • client-go/examples/README.md (1 hunks)
  • client-go/examples/basic-client/README.md (1 hunks)
  • client-go/examples/basic-client/main.go (1 hunks)
  • client-go/examples/controller-shim/README.md (1 hunks)
  • client-go/examples/controller-shim/main.go (1 hunks)
  • client-go/examples/fake-server/README.md (1 hunks)
  • client-go/examples/fake-server/main.go (1 hunks)
  • client-go/examples/streaming-daemon/README.md (1 hunks)
  • client-go/examples/streaming-daemon/main.go (1 hunks)
  • client-go/go.mod (1 hunks)
  • client-go/hack/apply-overlays.sh (1 hunks)
  • client-go/hack/boilerplate.go.txt (1 hunks)
  • client-go/hack/boilerplate_overlay.go.txt (1 hunks)
  • client-go/hack/overlays/client/versioned/clientset.go (1 hunks)
  • client-go/hack/overlays/client/versioned/integration_test.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1 hunks)
  • client-go/informers/externalversions/device/interface.go (1 hunks)
  • client-go/informers/externalversions/device/v1alpha1/gpu.go (1 hunks)
  • client-go/informers/externalversions/device/v1alpha1/interface.go (1 hunks)
  • client-go/informers/externalversions/factory.go (1 hunks)
  • client-go/informers/externalversions/generic.go (1 hunks)
  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go (1 hunks)
  • client-go/listers/device/v1alpha1/expansion_generated.go (1 hunks)
  • client-go/listers/device/v1alpha1/gpu.go (1 hunks)
  • client-go/nvgrpc/client_conn.go (1 hunks)
  • client-go/nvgrpc/client_conn_test.go (1 hunks)
  • client-go/nvgrpc/config.go (1 hunks)
  • client-go/nvgrpc/config_test.go (1 hunks)
  • client-go/nvgrpc/interceptors.go (1 hunks)
  • client-go/nvgrpc/interceptors_test.go (1 hunks)
  • client-go/nvgrpc/options.go (1 hunks)
  • client-go/nvgrpc/options_test.go (1 hunks)
  • client-go/nvgrpc/watcher.go (1 hunks)
  • client-go/nvgrpc/watcher_test.go (1 hunks)
  • client-go/version/version.go (1 hunks)
  • client-go/version/version_test.go (1 hunks)
  • event-exporter/pkg/transformer/cloudevents.go (1 hunks)
  • event-exporter/pkg/transformer/cloudevents_test.go (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • client-go/README.md
  • api/hack/boilerplate.go.txt
  • api/device/v1alpha1/doc.go
🚧 Files skipped from review as they are similar to previous changes (34)
  • client-go/hack/boilerplate.go.txt
  • client-go/nvgrpc/options_test.go
  • api/device/v1alpha1/register.go
  • client-go/examples/basic-client/README.md
  • .gitignore
  • client-go/version/version_test.go
  • client-go/hack/apply-overlays.sh
  • client-go/listers/device/v1alpha1/gpu.go
  • client-go/examples/streaming-daemon/README.md
  • client-go/nvgrpc/client_conn.go
  • client-go/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go
  • client-go/hack/overlays/client/versioned/clientset.go
  • api/device/v1alpha1/gpu_conversion_test.go
  • client-go/informers/externalversions/device/v1alpha1/gpu.go
  • client-go/listers/device/v1alpha1/expansion_generated.go
  • client-go/nvgrpc/options.go
  • client-go/version/version.go
  • client-go/examples/fake-server/main.go
  • client-go/examples/fake-server/README.md
  • client-go/informers/externalversions/device/interface.go
  • client-go/nvgrpc/interceptors_test.go
  • client-go/nvgrpc/client_conn_test.go
  • client-go/informers/externalversions/device/v1alpha1/interface.go
  • client-go/nvgrpc/interceptors.go
  • client-go/client/versioned/typed/device/v1alpha1/gpu.go
  • .versions.yaml
  • client-go/nvgrpc/config_test.go
  • api/device/v1alpha1/converter.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go
  • api/device/v1alpha1/gpu_conversion.go
  • client-go/client/versioned/fake/register.go
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_gpu.go
  • client-go/examples/basic-client/main.go
  • client-go/client/versioned/fake/doc.go
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.go: Follow standard Go conventions with gofmt and golint
Use structured logging via log/slog in Go code
Wrap errors with context using fmt.Errorf("context: %w", err) in Go code
Within retry.RetryOnConflict blocks, return errors without wrapping to preserve retry behavior
Use meaningful variable names such as synced over ok for cache sync checks
Use client-go for Kubernetes API interactions in Go code
Prefer informers over direct API calls for watching Kubernetes resources
Implement proper shutdown handling with context cancellation in Go code
Package-level godoc required for all Go packages
Function comments required for all exported Go functions
Use inline comments for complex logic only in Go code
TODO comments should reference issues in Go code
Extract informer event handler setup into helper methods
Use separate informers for different Kubernetes resource types

Files:

  • client-go/examples/streaming-daemon/main.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go
  • event-exporter/pkg/transformer/cloudevents_test.go
  • api/device/v1alpha1/zz_generated.deepcopy.go
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go
  • client-go/client/versioned/typed/device/v1alpha1/generated_expansion.go
  • client-go/client/versioned/integration_test.go
  • client-go/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/client/versioned/fake/clientset_generated.go
  • client-go/client/versioned/scheme/register.go
  • client-go/client/versioned/typed/device/v1alpha1/doc.go
  • client-go/informers/externalversions/factory.go
  • client-go/nvgrpc/watcher.go
  • client-go/nvgrpc/watcher_test.go
  • client-go/client/versioned/typed/device/v1alpha1/fake/doc.go
  • api/device/v1alpha1/gpu_types.go
  • event-exporter/pkg/transformer/cloudevents.go
  • client-go/examples/controller-shim/main.go
  • client-go/client/versioned/scheme/doc.go
  • api/device/v1alpha1/zz_generated.conversion.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/informers/externalversions/generic.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/nvgrpc/config.go
  • client-go/client/versioned/clientset.go
**/*_test.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*_test.go: Use envtest for testing Kubernetes controllers instead of fake clients
Use testify/assert and testify/require for assertions in Go tests
Write table-driven tests when testing multiple scenarios in Go
Name Go tests descriptively using format: TestFunctionName_Scenario_ExpectedBehavior

Files:

  • event-exporter/pkg/transformer/cloudevents_test.go
  • client-go/client/versioned/integration_test.go
  • client-go/nvgrpc/watcher_test.go
  • client-go/hack/overlays/client/versioned/integration_test.go
**/go.mod

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use go.mod for each service as a separate Go module with semantic import versioning

Files:

  • client-go/go.mod
  • api/go.mod
🧠 Learnings (11)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Extract informer event handler setup into helper methods

Applied to files:

  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go
  • client-go/informers/externalversions/generic.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use separate informers for different Kubernetes resource types

Applied to files:

  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go
  • client-go/informers/externalversions/factory.go
  • client-go/informers/externalversions/generic.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Prefer informers over direct API calls for watching Kubernetes resources

Applied to files:

  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go
  • client-go/informers/externalversions/factory.go
  • client-go/nvgrpc/watcher.go
  • client-go/go.mod
  • client-go/informers/externalversions/generic.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Use `envtest` for testing Kubernetes controllers instead of fake clients

Applied to files:

  • client-go/client/versioned/integration_test.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/client/versioned/fake/clientset_generated.go
  • client-go/examples/README.md
  • client-go/nvgrpc/watcher_test.go
  • client-go/client/versioned/typed/device/v1alpha1/fake/doc.go
  • client-go/go.mod
  • client-go/hack/overlays/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use meaningful variable names such as `synced` over `ok` for cache sync checks

Applied to files:

  • client-go/client/versioned/fake/clientset_generated.go
  • client-go/hack/overlays/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code

Applied to files:

  • client-go/client/versioned/scheme/register.go
  • client-go/client/versioned/typed/device/v1alpha1/doc.go
  • api/Makefile
  • client-go/examples/README.md
  • client-go/nvgrpc/watcher.go
  • client-go/go.mod
  • client-go/client/versioned/scheme/doc.go
  • api/go.mod
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/Makefile
  • client-go/hack/boilerplate_overlay.go.txt
  • client-go/DEVELOPMENT.md
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Package-level godoc required for all Go packages

Applied to files:

  • client-go/client/versioned/typed/device/v1alpha1/doc.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Keep Go dependencies minimal and up-to-date

Applied to files:

  • api/Makefile
  • client-go/go.mod
  • api/go.mod
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Implement proper shutdown handling with context cancellation in Go code

Applied to files:

  • client-go/informers/externalversions/factory.go
  • client-go/nvgrpc/watcher.go
  • client-go/hack/overlays/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/go.mod : Use `go.mod` for each service as a separate Go module with semantic import versioning

Applied to files:

  • client-go/go.mod
  • api/go.mod
🧬 Code graph analysis (11)
client-go/examples/streaming-daemon/main.go (5)
client-go/client/versioned/clientset.go (2)
  • New (95-99)
  • NewForConfigAndClient (64-81)
client-go/client/versioned/typed/device/v1alpha1/device_client.go (2)
  • New (74-79)
  • NewForConfigAndClient (55-60)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (2)
  • New (58-63)
  • NewForConfigAndClient (39-44)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/nvgrpc/client_conn.go (1)
  • ClientConnFor (27-72)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (2)
api/gen/go/device/v1alpha1/gpu_grpc.pb.go (1)
  • GpuService_WatchGpusClient (100-100)
api/device/v1alpha1/gpu_conversion.go (1)
  • FromProto (25-32)
api/device/v1alpha1/zz_generated.deepcopy.go (1)
api/device/v1alpha1/gpu_types.go (4)
  • GPU (55-61)
  • GPUList (67-71)
  • GPUSpec (24-30)
  • GPUStatus (35-45)
client-go/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1)
client-go/client/versioned/typed/device/v1alpha1/gpu.go (1)
  • GPUInterface (38-43)
client-go/client/versioned/integration_test.go (3)
client-go/client/versioned/clientset.go (2)
  • NewForConfigAndClient (64-81)
  • New (95-99)
client-go/hack/overlays/client/versioned/clientset.go (2)
  • NewForConfigAndClient (48-65)
  • New (79-83)
api/gen/go/device/v1alpha1/gpu.pb.go (12)
  • WatchGpusResponse (696-713)
  • WatchGpusResponse (726-726)
  • WatchGpusResponse (741-743)
  • Gpu (159-169)
  • Gpu (182-182)
  • Gpu (197-199)
  • ObjectMeta (40-53)
  • ObjectMeta (66-66)
  • ObjectMeta (81-83)
  • GpuSpec (277-285)
  • GpuSpec (298-298)
  • GpuSpec (313-315)
client-go/nvgrpc/watcher_test.go (1)
client-go/nvgrpc/watcher.go (1)
  • NewWatcher (47-62)
client-go/examples/controller-shim/main.go (7)
client-go/client/versioned/clientset.go (1)
  • New (95-99)
client-go/informers/externalversions/device/interface.go (1)
  • New (37-39)
client-go/informers/externalversions/device/v1alpha1/interface.go (1)
  • New (36-38)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/informers/externalversions/factory.go (1)
  • NewSharedInformerFactory (91-93)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
api/device/v1alpha1/gpu_types.go (1)
  • GPU (55-61)
api/device/v1alpha1/zz_generated.conversion.go (3)
api/gen/go/device/v1alpha1/gpu.pb.go (21)
  • Gpu (159-169)
  • Gpu (182-182)
  • Gpu (197-199)
  • ObjectMeta (40-53)
  • ObjectMeta (66-66)
  • ObjectMeta (81-83)
  • Condition (380-398)
  • Condition (411-411)
  • Condition (426-428)
  • GpuList (223-230)
  • GpuList (243-243)
  • GpuList (258-260)
  • ListMeta (100-112)
  • ListMeta (125-125)
  • ListMeta (140-142)
  • GpuSpec (277-285)
  • GpuSpec (298-298)
  • GpuSpec (313-315)
  • GpuStatus (325-333)
  • GpuStatus (346-346)
  • GpuStatus (361-363)
api/device/v1alpha1/gpu_types.go (3)
  • GPU (55-61)
  • GPUList (67-71)
  • GPUSpec (24-30)
api/device/v1alpha1/converter.go (4)
  • FromProtobufTypeMeta (107-112)
  • FromProtobufTimestamp (123-128)
  • FromProtobufListTypeMeta (115-120)
  • ToProtobufTimestamp (131-133)
client-go/informers/externalversions/generic.go (1)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
client-go/nvgrpc/config.go (1)
client-go/version/version.go (1)
  • UserAgent (28-35)
client-go/client/versioned/clientset.go (4)
client-go/client/versioned/typed/device/v1alpha1/device_client.go (6)
  • DeviceV1alpha1Interface (25-28)
  • DeviceV1alpha1Client (31-34)
  • NewForConfig (43-51)
  • NewForConfigAndClient (55-60)
  • NewForConfigOrDie (64-71)
  • New (74-79)
client-go/hack/overlays/client/versioned/clientset.go (5)
  • Clientset (17-19)
  • NewForConfig (32-44)
  • NewForConfigAndClient (48-65)
  • NewForConfigOrDie (69-76)
  • New (79-83)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/nvgrpc/client_conn.go (1)
  • ClientConnFor (27-72)
🪛 checkmake (0.2.2)
client-go/Makefile

[warning] 187-187: Target "tools" should be declared PHONY.

(phonydeclared)

🪛 LanguageTool
client-go/DEVELOPMENT.md

[style] ~77-~77: This phrase is redundant. Consider using “inside”.
Context: ... informers/) The directory structure inside of hack/overlays/ *must exactly mirror...

(OUTSIDE_OF)

🪛 markdownlint-cli2 (0.18.1)
client-go/DEVELOPMENT.md

10-10: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


11-11: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)

🔇 Additional comments (66)
client-go/hack/boilerplate_overlay.go.txt (1)

1-16: LGTM!

The boilerplate header template is correctly formatted with the standard Apache 2.0 license, proper copyright year, and an appropriate "DO NOT EDIT" generation comment. This aligns with the overlay pattern introduced in the PR for consistent code generation.

event-exporter/pkg/transformer/cloudevents.go (1)

60-60: LGTM: String representation improves CloudEvent readability.

The change from numeric enum to string representation (event.RecommendedAction.String()) makes CloudEvent payloads more human-readable and aligns with the v1alpha1 GPU API design where RecommendedAction is represented as a string.

client-go/examples/README.md (1)

1-38: LGTM: Clear and comprehensive example documentation.

The README effectively documents the three integration patterns with appropriate complexity levels and provides clear prerequisites and setup instructions for local development.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1)

21-24: Verify: Nil ClientConn could cause NPE in tests.

The ClientConn() method returns a typed nil (*grpc.ClientConn cast to grpc.ClientConnInterface). While the comment clearly states the fake uses ObjectTracker, any test code attempting to invoke methods on the returned interface will panic with a nil pointer dereference.

This pattern follows standard client-go conventions where fake clients return nil for transport-layer interfaces. However, verify that all test code using this fake client avoids calling ClientConn() or handles the nil case appropriately.

Based on learnings, consider using envtest for controller testing scenarios instead of fake clients where a more realistic environment is beneficial.

client-go/go.mod (1)

1-15: LGTM: Module structure follows best practices.

The module declaration, replace directive for the local api module, and dependency selection align with the coding guidelines for separate Go modules and Kubernetes client patterns.

As per coding guidelines, the separate module structure with semantic import versioning and use of client-go for Kubernetes API interactions is appropriate.

client-go/informers/externalversions/internalinterfaces/factory_interfaces.go (1)

28-38: LGTM: Standard informer factory interfaces.

The interface definitions follow established client-go patterns for informer factories, enabling proper informer lifecycle management and resource-specific informer creation.

As per coding guidelines, these interfaces support the preferred pattern of using informers over direct API calls for watching Kubernetes resources.

client-go/hack/overlays/client/versioned/integration_test.go (2)

64-129: LGTM!

The Get, List, and Watch subtests are well-structured with proper timeout handling in the Watch test and clear assertions. Good use of select with timeouts to avoid test hangs.


131-182: LGTM!

The Informer and Lister sync test follows best practices: instantiating the informer before starting the factory, using cache.WaitForCacheSync correctly, and polling for eventual consistency with wait.PollUntilContextTimeout.

client-go/informers/externalversions/generic.go (1)

1-60: LGTM!

This is generated code that correctly implements the GenericInformer interface and wires the ForResource method to handle the gpus resource under the device.nvidia.com/v1alpha1 group version. The implementation aligns with the SchemeGroupVersion defined in api/device/v1alpha1/register.go.

client-go/nvgrpc/config.go (2)

51-67: LGTM!

The Default() method follows a sensible defaulting chain: environment variable → default constant. Using logr.Discard() as the fallback logger is appropriate.


69-89: LGTM!

The Validate() method provides clear error messages with context. GetLogger() is appropriately defensive, returning a discard logger even if Default() wasn't called.

client-go/nvgrpc/watcher_test.go (6)

31-58: LGTM!

Well-structured test that verifies normal event flow through the watcher. Good pattern of closing the events channel to signal completion.


60-83: LGTM!

Good edge case coverage verifying that unknown event types are silently ignored while subsequent valid events are processed correctly.


85-117: LGTM!

Good table-driven test following coding guidelines. Correctly verifies that gRPC error codes are translated to appropriate metav1.Status responses (e.g., OutOfRangeStatusReasonExpired with HTTP 410).


119-151: LGTM!

Correctly verifies that the stream terminates after the first error and the second error is never delivered. Good use of timeout to prevent test hangs.


153-176: LGTM!

The test correctly verifies that Stop() cancels the context and closes the result channel. The short sleep on line 159 is a pragmatic approach to allow the receive goroutine to start.


178-238: LGTM!

Well-designed test doubles. FakeSource.Close() correctly guards against double-close panics, and Next() properly prioritizes error injection over channel events.

api/go.mod (1)

3-3: No issues to address. Go 1.25.0 and k8s.io/apimachinery v0.34.2 are valid, stable versions appropriate for production use.

client-go/nvgrpc/watcher.go (2)

84-137: LGTM! Well-structured receive loop with proper event handling.

The receive loop correctly:

  • Handles EOF and cancellation as normal termination
  • Maps event type strings to Kubernetes watch.EventType constants
  • Processes ERROR events explicitly
  • Provides detailed logging at appropriate verbosity levels
  • Respects the done channel for clean shutdown

139-164: LGTM! Proper error-to-status conversion for informer compatibility.

The sendError() method correctly:

  • Converts gRPC status to metav1.Status
  • Maps OutOfRange and ResourceExhausted to HTTP 410 (Expired) with StatusReasonExpired, which triggers informer resync
  • Respects the done channel to avoid blocking on shutdown

This is critical for informer reliability.

client-go/informers/externalversions/factory.go (3)

122-144: LGTM! Safe concurrent Start() implementation.

The Start() method correctly:

  • Checks shuttingDown flag to prevent starting during shutdown
  • Tracks started informers to allow multiple calls
  • Captures the loop variable in each goroutine
  • Uses WaitGroup for proper lifecycle management

146-153: LGTM! Proper shutdown coordination.

The Shutdown() method correctly sets the flag under lock and waits for all goroutines to complete. The implementation allows multiple concurrent calls safely.


176-198: LGTM! Correct informer creation with per-type customization.

The InformerFor() method correctly:

  • Returns existing informers for idempotency
  • Applies per-type custom resync periods or falls back to default
  • Applies the shared transform function
  • Properly synchronizes access to shared state
event-exporter/pkg/transformer/cloudevents_test.go (1)

101-102: LGTM! Test correctly updated for API refactor.

The test expectation correctly changed from the int32 protobuf enum value pb.RecommendedAction_RESTART_VM to the string representation "RESTART_VM". This aligns with the PR's API changes where GPUStatus.RecommendedAction is now a string field in the v1alpha1 internal types.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1)

9-27: LGTM! Clean stream adapter implementation.

The gpuStreamAdapter correctly:

  • Wraps the gRPC stream client
  • Implements the Source interface expected by the Watcher
  • Converts protobuf responses to internal runtime.Object via FromProto
  • Returns event type strings and objects for downstream processing
  • Properly closes the stream via CloseSend()

This adapter enables the nvgrpc Watcher to work with GPU watch streams.

client-go/examples/streaming-daemon/main.go (4)

36-46: LGTM! Proper initialization and configuration.

The setup correctly:

  • Initializes structured logging with stdr
  • Reads configuration from environment variable with sensible default
  • Uses standard Unix domain socket path for local gRPC connection

49-58: LGTM! Well-implemented interceptors for observability.

The interceptors correctly:

  • tracingInterceptor: Injects x-request-id metadata for request tracing
  • watchMonitorInterceptor: Logs the start of watch streams for monitoring

These demonstrate proper custom interceptor usage for cross-cutting concerns.


68-82: LGTM! Proper connection and clientset initialization.

The initialization correctly:

  • Creates nvgrpc.Config with the target
  • Establishes connection with custom dial options
  • Defers connection cleanup
  • Creates versioned clientset from the connection
  • Handles initialization errors appropriately

This demonstrates the manual connection management pattern when fine-grained control over interceptors is needed.


97-143: LGTM! Robust watch event processing.

The watch loop correctly:

  • Establishes the watch with proper error handling
  • Defers watcher cleanup
  • Handles closed channel, error events, and unknown object types
  • Uses meta.IsStatusConditionTrue to derive GPU readiness from conditions
  • Respects context timeout for clean shutdown
  • Provides informative logging at each step

This is a good reference implementation for processing watch events.

client-go/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1)

25-40: LGTM!

The fake client implementation follows standard Kubernetes client-go fake patterns. The ClientConn() method returning nil is well-documented and appropriate for an in-memory fake that uses ObjectTracker instead of actual gRPC connections.

api/proto/device/v1alpha1/gpu.proto (1)

53-77: Well-designed resource structure.

The Gpu and GpuList messages correctly follow the Kubernetes Resource Model pattern with proper metadata, spec, and status separation. The field numbering is consistent and the documentation is clear.

client-go/client/versioned/fake/clientset_generated.go (1)

39-65: LGTM!

The NewSimpleClientset function correctly sets up the fake clientset with an ObjectTracker, registers reactors for CRUD operations, and configures watch handling. The implementation follows established Kubernetes client-go fake patterns.

client-go/client/versioned/scheme/register.go (1)

28-54: LGTM!

The scheme registration follows standard Kubernetes client-go patterns. The exported AddToScheme function enables scheme composition with other clientsets, and the init() function properly registers the v1 group version and device types.

api/device/v1alpha1/gpu_types.go (1)

21-70: Well-structured GPU type definitions.

The type definitions correctly follow Kubernetes CRD conventions with proper embedding of TypeMeta, ObjectMeta, and ListMeta. The code-gen markers are appropriately configured for a non-namespaced, read-only resource.

api/device/v1alpha1/zz_generated.deepcopy.go (1)

1-125: LGTM!

The auto-generated deepcopy implementations correctly handle all fields including nested slices (Items, Conditions) with proper nil checks and element-wise deep copying. The generated code aligns with the type definitions in gpu_types.go.

client-go/examples/controller-shim/main.go (1)

120-142: LGTM on the reconciler implementation.

The GPUReconciler is cleanly implemented with proper error handling using client.IgnoreNotFound. The SetupWithManager method correctly registers the controller for GPU resources.

client-go/client/versioned/integration_test.go (7)

1-48: LGTM! Well-structured integration test setup.

The test establishes an in-process gRPC server via bufconn, properly wires the mock GPU service, and sets up context with timeout for cancellation. The import organization and test scaffolding follow good patterns.


49-102: Get and List subtests look correct.

The basic Get and List operations are properly tested with appropriate assertions on the returned data.


104-145: Watch flow test correctly validates initial snapshot and live events.

The test properly consumes the initial ADDED event, triggers a MODIFIED event via the mock, and verifies the event type and resource version propagation.


147-198: Informer and Lister sync test validates cache synchronization.

The test correctly uses cache.WaitForCacheSync and wait.PollUntilContextTimeout to verify the informer cache updates with watch events.


200-268: Controller-runtime compatibility test validates cache integration.

The test properly wires the controller-runtime cache with custom NewInformer to inject the GPU informer, demonstrating seamless integration between the gRPC-backed clientset and controller-runtime patterns.


273-293: Mock server initialization is clean.

The mock properly uses a buffered channel for watch events and initializes with seed GPU data.


295-353: Mock server implementations are thread-safe and well-structured.

  • GetGpu and ListGpus properly use RLock for concurrent reads
  • WatchGpus correctly sends initial snapshot before entering live event loop
  • Proper context cancellation handling in the watch loop
client-go/client/versioned/clientset.go (1)

1-99: LGTM! Clean clientset implementation following client-go patterns.

The generated clientset correctly:

  • Exposes a minimal Interface for dependency injection
  • Uses shallow copies to prevent config mutation
  • Provides appropriate constructor variants (NewForConfig, NewForConfigAndClient, NewForConfigOrDie, New)
  • Validates nil inputs with descriptive error messages
api/Makefile (3)

19-57: Configuration section is well-organized.

Good use of helper variables for string manipulation, clear module/version definitions, and robust GO_VERSION fallback logic.


93-107: Code generation workflow is properly structured.

The code-gen target correctly chains dependencies and runs go mod tidy to synchronize after generation.


191-202: go-install-tool macro is robust.

Uses versioned symlinks to avoid re-downloading and properly sets GOTOOLCHAIN for consistent tool installation.

client-go/client/versioned/typed/device/v1alpha1/device_client.go (1)

1-89: LGTM! Well-designed device client implementation.

The generated client correctly:

  • Exposes DeviceV1alpha1Interface with ClientConn() and GPUsGetter
  • Provides nil-safe ClientConn() method (lines 84-86)
  • Uses logr.Discard() as sensible default when config isn't available
  • Follows shallow-copy pattern to prevent config mutation
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1)

9-73: LGTM! Overlay implementation matches expected pattern.

The overlay provides the same interface and constructor patterns as the generated client, enabling custom gRPC logic injection.

client-go/Makefile (4)

19-84: Configuration section is well-organized and consistent with api/Makefile.

Good use of shared patterns: string manipulation helpers, versioned tool management, and yq-based version loading from .versions.yaml.


100-149: Code generation workflow properly orchestrates multi-tool pipeline.

The code-gen target correctly chains client-gen → copy-overlays → lister-gen → informer-gen, ensuring overlays are applied before dependent generators run.


105-113: Build and test exclusions are appropriate.

Excluding /hack/overlays/, /examples/, and test-infrastructure paths from build/test ensures only production code is validated.


198-213: go-install-tool macro is consistent with api/Makefile.

Uses versioned symlinks and GOTOOLCHAIN for reproducible tool installation.

api/device/v1alpha1/zz_generated.conversion.go (13)

23-33: LGTM!

The condition conversion properly handles nil input, correctly converts the Status field to v1.ConditionStatus, and uses the timestamp helper appropriately.


34-49: LGTM!

The list conversion correctly handles nil input, properly preserves the distinction between nil and empty slices, and efficiently allocates the Items slice only when needed.


50-56: LGTM!

The ListMeta conversion correctly extracts the ResourceVersion field with proper nil handling.


57-64: LGTM!

The ObjectMeta conversion correctly extracts the Name and ResourceVersion fields with proper nil handling. The minimal field set aligns with the node-local gRPC API design.


65-71: LGTM!

The Spec conversion correctly maps the Uuid field from protobuf to the UUID field in the internal type with proper nil handling.


72-84: LGTM!

The Status conversion properly handles nil checks for both the source and the Conditions slice, preserves the nil vs. empty slice distinction, and correctly maps all fields.


85-91: LGTM!

The conversion correctly transforms the internal GPU to protobuf format. TypeMeta is appropriately omitted from the protobuf message (it's reconstructed on the wire).


92-100: LGTM!

The condition conversion correctly transforms the internal type to protobuf format, with proper type conversion for the Status field and correct timestamp helper usage.


101-115: LGTM!

The list conversion properly handles nil input, preserves the nil vs. empty slice distinction, and correctly converts each item to protobuf format.


116-120: LGTM!

The ListMeta conversion correctly extracts the ResourceVersion field and returns the protobuf message.


121-126: LGTM!

The ObjectMeta conversion correctly extracts the Name and ResourceVersion fields for the protobuf message, consistent with the minimal metadata design.


127-131: LGTM!

The Spec conversion correctly maps the UUID field to the protobuf Uuid field.


132-142: LGTM!

The Status conversion properly handles the Conditions slice with nil checking, preserves the nil vs. empty distinction, and correctly maps all fields to protobuf format.

Copy link
Contributor

@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: 6

♻️ Duplicate comments (16)
client-go/version/version.go (1)

22-23: Fix typo in comment.

Line 23 contains "It i set" which should be "It is set".

🔎 Proposed fix
 // GitVersion is the semantic version of the client.
-// It i set at build time via -ldflags
+// It is set at build time via -ldflags
 // e.g., -ldflags "-X 'github.com/nvidia/nvsentinel/client-go/version.GitVersion=v1.2.3'"
client-go/go.mod (1)

3-3: Update go version to 1.25.5 (latest stable patch release).

Line 3 specifies go 1.25.0, but the latest patch is 1.25.5, which includes security fixes released December 2, 2025 for crypto/x509 and other packages. Upgrade to pick up these critical updates.

🔎 Proposed fix
-go 1.25.0
+go 1.25.5

After updating, run go mod tidy and verify your CI build/test pipeline passes.

client-go/examples/basic-client/README.md (1)

12-12: Incorrect relative path to Fake Server.

The path ../../fake-server is incorrect. Since this README is in client-go/examples/basic-client/, the fake server at client-go/examples/fake-server/ should be referenced as ../fake-server.

🔎 Proposed fix
-1. Ensure the [Fake Server](../../fake-server) is running.
+1. Ensure the [Fake Server](../fake-server) is running.
.versions.yaml (1)

49-51: Verify goverter version exists.

The specified goverter: 'v1.9.2' may not be a valid release. The latest known stable version is v1.8.2. The Kubernetes code-generator tools (v0.34.2) are compatible with client-go v0.34.1.

#!/bin/bash
# Verify goverter releases
curl -s https://api.github.com/repos/jmattheis/goverter/releases | jq '.[0:5] | .[] | {tag_name, published_at}'
client-go/examples/streaming-daemon/README.md (1)

13-13: Incorrect relative path to Fake Server.

Same issue as basic-client README—the path ../../fake-server should be ../fake-server to correctly reference client-go/examples/fake-server/.

🔎 Proposed fix
-1. Ensure the [Fake Server](../../fake-server) is running.
+1. Ensure the [Fake Server](../fake-server) is running.
client-go/examples/controller-shim/main.go (2)

58-62: The informer factory is never started.

The comment on line 60 states the Manager will start the injected informer, but controller-runtime only starts informers created through its own cache machinery. The factory.Start() must be called explicitly for the gRPC-backed informer to populate its cache.

🔎 Proposed fix
 	factory := informers.NewSharedInformerFactory(clientset, 10*time.Minute)
 	gpuInformer := factory.Device().V1alpha1().GPUs().Informer()

+	// Start the factory before creating the manager. The informer must be running
+	// and synced before the manager attempts to use the cache.
+	stopCh := make(chan struct{})
+	go factory.Start(stopCh)
+	factory.WaitForCacheSync(stopCh)

Note: Ensure stopCh is closed on shutdown (e.g., via defer close(stopCh) after signal handling setup, or tie to ctx.Done()).


78-96: Returning nil for non-GPU objects may cause panics.

When NewInformer returns nil (line 95) for objects other than *devicev1alpha1.GPU, controller-runtime may attempt to use the nil informer, leading to nil pointer dereferences. Return a default informer for unhandled types.

🔎 Proposed fix
 			NewInformer: func(lw toolscache.ListerWatcher, obj runtime.Object, resync time.Duration, indexers toolscache.Indexers) toolscache.SharedIndexInformer {
 				if _, ok := obj.(*devicev1alpha1.GPU); ok {
 					// ... existing GPU handling ...
 					return gpuInformer
 				}
-				return nil
+				// Fall back to the default informer for non-GPU objects.
+				return toolscache.NewSharedIndexInformer(lw, obj, resync, indexers)
 			},
api/Makefile (2)

128-128: Undefined variable API_PKGS_COMMA will cause build failure.

Line 128 references API_PKGS_COMMA, but this variable is not defined anywhere in the Makefile. Only API_VERSIONS_COMMA (line 31) and API_PKGS (line 34) are defined. This will pass an empty string to --bounding-dirs, causing deepcopy-gen to fail or behave incorrectly.

🔎 Proposed fix

Add the missing variable definition after line 34:

 # Helper for tools that need full package paths
 API_PKGS := $(foreach version,$(API_VERSIONS),$(MODULE_NAME)/$(version))
+
+# Helper for tools that need comma-separated package paths
+API_PKGS_COMMA := $(subst $(SPACE),$(COMMA),$(API_PKGS))

134-134: Minor typo: double period in help text.

🔎 Proposed fix
-conversion-gen: $(GOVERTER) clean-conversion ## Generate conversion code..
+conversion-gen: $(GOVERTER) clean-conversion ## Generate conversion code.
api/proto/device/v1alpha1/gpu.proto (1)

27-51: Inconsistent indentation in comments (duplicate finding).

Lines 35-37 and 47-48 use tabs while surrounding lines use spaces. This was already flagged in a previous review.

client-go/hack/overlays/client/versioned/integration_test.go (1)

210-214: Avoid calling t.Errorf from a goroutine.

This is still a race condition risk. Calling t.Errorf from within a goroutine is unsafe and can cause races or panics if the test completes before the goroutine executes.

client-go/client/versioned/integration_test.go (1)

226-230: Goroutine error won't fail the test.

t.Errorf called from within a goroutine won't properly fail the test. This is the same issue flagged previously.

client-go/examples/fake-server/main.go (1)

185-193: ListMeta is not populated in the response.

The GpuList response doesn't include metadata.resource_version, which is needed for clients to establish a watch from a consistent point (List-then-Watch pattern). This was flagged in a previous review.

client-go/nvgrpc/watcher.go (1)

64-77: Potential race condition in Stop() with double-close protection.

The select on lines 72-76 attempts to prevent double-close of w.done, but there's a race window between checking and closing. Additionally, receive() calls defer w.Stop() (line 90), which could race with an external Stop() call. This was flagged in a previous review - consider using sync.Once for safer shutdown.

api/device/v1alpha1/converter.go (1)

106-120: APIVersion should include the group, not just the version.

The Kubernetes TypeMeta.APIVersion field should be in the format group/version. Using SchemeGroupVersion.Version produces only v1alpha1, but the correct value should be device.nvidia.com/v1alpha1. Use SchemeGroupVersion.String() instead.

 func FromProtobufTypeMeta(_ *pb.Gpu) metav1.TypeMeta {
 	return metav1.TypeMeta{
 		Kind:       "GPU",
-		APIVersion: SchemeGroupVersion.Version,
+		APIVersion: SchemeGroupVersion.String(),
 	}
 }

 func FromProtobufListTypeMeta(_ *pb.GpuList) metav1.TypeMeta {
 	return metav1.TypeMeta{
 		Kind:       "GPUList",
-		APIVersion: SchemeGroupVersion.Version,
+		APIVersion: SchemeGroupVersion.String(),
 	}
 }
client-go/informers/externalversions/factory.go (1)

200-224: Documentation references non-existent method.

The example references factory.WaitForStop() on line 208, but the actual method is Shutdown(). Since this is generated code, this should be fixed in the generator template.

🧹 Nitpick comments (19)
client-go/nvgrpc/config_test.go (3)

20-59: Use testify assertions per coding guidelines.

The test logic is correct and follows table-driven test patterns well. However, per the coding guidelines, Go tests should use testify/assert or testify/require for assertions instead of basic t.Errorf.

🔎 Proposed refactor using testify/assert
 import (
 	"testing"
+	
+	"github.com/stretchr/testify/assert"
 )

 func TestConfig_Default_TargetPrecedence(t *testing.T) {
 	tests := []struct {
 		name       string
 		argTarget  string
 		envTarget  string
 		wantTarget string
 	}{
 		{
 			name:       "Explicit target is preserved",
 			argTarget:  "unix:///arg.sock",
 			envTarget:  "unix:///env.sock",
 			wantTarget: "unix:///arg.sock",
 		},
 		{
 			name:       "Env var used when target is empty",
 			argTarget:  "",
 			envTarget:  "unix:///env.sock",
 			wantTarget: "unix:///env.sock",
 		},
 		{
 			name:       "Default used when both are empty",
 			argTarget:  "",
 			envTarget:  "",
 			wantTarget: DefaultNvidiaDeviceAPISocket,
 		},
 	}

 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			t.Setenv(NvidiaDeviceAPITargetEnvVar, tt.envTarget)

 			cfg := &Config{Target: tt.argTarget}
 			cfg.Default()

-			if cfg.Target != tt.wantTarget {
-				t.Errorf("Target = %q, want %q", cfg.Target, tt.wantTarget)
-			}
+			assert.Equal(t, tt.wantTarget, cfg.Target)
 		})
 	}
 }

As per coding guidelines for **/*_test.go.


61-80: Use testify assertions and validate the actual default UserAgent value.

The test correctly validates preservation of custom UserAgent, but the first subtest only checks that UserAgent is non-empty rather than validating it matches the expected default from version.UserAgent(). Additionally, per coding guidelines, use testify/assert for assertions.

🔎 Proposed refactor with testify and explicit default validation
 import (
 	"testing"
+	
+	"github.com/stretchr/testify/assert"
+	"github.com/nvidia/nvidia-device-api/client-go/version"
 )

 func TestConfig_Default_UserAgent(t *testing.T) {
 	t.Run("Populates default UserAgent if empty", func(t *testing.T) {
 		cfg := &Config{}
 		cfg.Default()

-		if cfg.UserAgent == "" {
-			t.Error("UserAgent should have been populated with version-based default")
-		}
+		assert.Equal(t, version.UserAgent(), cfg.UserAgent)
 	})

 	t.Run("Preserves custom UserAgent", func(t *testing.T) {
 		custom := "my-custom-agent/1.0"
 		cfg := &Config{UserAgent: custom}
 		cfg.Default()

-		if cfg.UserAgent != custom {
-			t.Errorf("UserAgent = %q, want %q", cfg.UserAgent, custom)
-		}
+		assert.Equal(t, custom, cfg.UserAgent)
 	})
 }

As per coding guidelines for **/*_test.go.


82-120: Use testify assertions per coding guidelines.

The validation test logic is correct and provides good coverage of both valid and invalid configurations. However, per the coding guidelines, Go tests should use testify/assert or testify/require for assertions.

🔎 Proposed refactor using testify/assert
 import (
 	"testing"
+	
+	"github.com/stretchr/testify/assert"
 )

 func TestConfig_Validate(t *testing.T) {
 	tests := []struct {
 		name    string
 		cfg     Config
 		wantErr bool
 	}{
 		{
 			name: "Valid config",
 			cfg: Config{
 				Target:    "unix:///var/run/test.sock",
 				UserAgent: "test/1.0",
 			},
 			wantErr: false,
 		},
 		{
 			name: "Missing target",
 			cfg: Config{
 				UserAgent: "test/1.0",
 			},
 			wantErr: true,
 		},
 		{
 			name: "Missing user agent",
 			cfg: Config{
 				Target: "unix:///var/run/test.sock",
 			},
 			wantErr: true,
 		},
 	}

 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			err := tt.cfg.Validate()
-			if (err != nil) != tt.wantErr {
-				t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr)
-			}
+			if tt.wantErr {
+				assert.Error(t, err)
+			} else {
+				assert.NoError(t, err)
+			}
 		})
 	}
 }

As per coding guidelines for **/*_test.go.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1)

17-24: Consider clarifying typed nil behavior or improving implementation.

The method returns a typed nil pointer (*grpc.ClientConn) as grpc.ClientConnInterface. This creates an interface value that is non-nil (due to containing type information) but holds a nil pointer—a common Go interface gotcha that can confuse callers checking conn != nil.

While the comment documents that fakes use ObjectTracker rather than gRPC, consider one of these alternatives for clarity:

  1. Explicitly document that callers should not invoke ClientConn() on fakes
  2. Return a stub that panics with a clear message if any gRPC method is invoked
  3. Add a comment warning about the nil pointer behavior
💡 Alternative: panic on usage
 // ClientConn returns a ClientConn that is used to communicate
 // with gRPC server by this client implementation.
 //
-// Note: the Fake implementation uses the ObjectTracker memory store, not an actual gRPC connection.
+// Note: the Fake implementation uses the ObjectTracker memory store, not an actual gRPC connection.
+// Calling this method on a fake client is not supported and will return a nil connection.
 func (c *FakeDeviceV1alpha1) ClientConn() grpc.ClientConnInterface {
-	var ret *grpc.ClientConn
-	return ret
+	// Returning typed nil to satisfy interface contract.
+	// Callers should not use ClientConn on fake implementations.
+	return (*grpc.ClientConn)(nil)
 }

Or alternatively, panic explicitly:

 func (c *FakeDeviceV1alpha1) ClientConn() grpc.ClientConnInterface {
-	var ret *grpc.ClientConn
-	return ret
+	panic("ClientConn() should not be called on fake client implementations")
 }
client-go/DEVELOPMENT.md (2)

10-11: Minor: Fix list indentation for markdown consistency.

Static analysis flags inconsistent indentation (4 spaces instead of 2) for nested list items.

🔎 Proposed fix
 * **yq**: Required to parse version configuration.
-    * *macOS*: `brew install yq`
-    * *Linux*: See [yq installation](https://github.com/mikefarah/yq)
+  * *macOS*: `brew install yq`
+  * *Linux*: See [yq installation](https://github.com/mikefarah/yq)

77-77: Nitpick: Remove redundant phrasing.

"inside of" can be simplified to "inside" for conciseness.

🔎 Proposed fix
-The directory structure inside of `hack/overlays/` **must exactly mirror** the structure of the generated code.
+The directory structure inside `hack/overlays/` **must exactly mirror** the structure of the generated code.
client-go/Makefile (1)

187-187: Declare tools target as PHONY.

The tools target should be marked .PHONY for consistency with other non-file-generating targets in this Makefile.

🔎 Proposed fix

Add before line 187:

+.PHONY: tools
 tools: $(CLIENT_GEN) $(LISTER_GEN) $(INFORMER_GEN)

Based on static analysis hint from checkmake.

client-go/nvgrpc/options_test.go (1)

48-64: Consider using testify assertions for consistency.

The test uses manual error checks with t.Errorf. Per coding guidelines, prefer testify/assert or testify/require for assertions in Go tests.

🔎 Proposed refactor using testify
 import (
 	"context"
 	"testing"
 
 	"github.com/go-logr/logr"
+	"github.com/stretchr/testify/assert"
 	"google.golang.org/grpc"
 )

Then update the assertions:

 	t.Run("Logger is correctly assigned", func(t *testing.T) {
-		if dOpts.logger != testLogger {
-			t.Errorf("expected logger to be set, got %v", dOpts.logger)
-		}
+		assert.Equal(t, testLogger, dOpts.logger, "logger should be set correctly")
 	})
 
 	t.Run("Unary interceptors are correctly appended", func(t *testing.T) {
-		if len(dOpts.unaryInterceptors) != 2 {
-			t.Errorf("expected 2 unary interceptors, got %d", len(dOpts.unaryInterceptors))
-		}
+		assert.Len(t, dOpts.unaryInterceptors, 2, "should have 2 unary interceptors")
 	})
 
 	t.Run("Stream interceptors are correctly appended", func(t *testing.T) {
-		if len(dOpts.streamInterceptors) != 2 {
-			t.Errorf("expected 2 stream interceptors, got %d", len(dOpts.streamInterceptors))
-		}
+		assert.Len(t, dOpts.streamInterceptors, 2, "should have 2 stream interceptors")
 	})

As per coding guidelines for Go tests.

client-go/nvgrpc/interceptors_test.go (2)

29-66: Consider using testify assertions for better test output.

The tests currently use t.Fatalf for assertions. Per coding guidelines, prefer testify/assert or testify/require for more informative failure messages and better test maintainability.

🔎 Refactor to use testify/require
 import (
 	"context"
 	"errors"
 	"testing"
 	"time"
 
 	logr "github.com/go-logr/logr/testing"
+	"github.com/stretchr/testify/require"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 )
 			err := interceptor(context.Background(), tt.method, nil, nil, nil, invoker)
-			if !errors.Is(err, tt.invokerErr) {
-				t.Fatalf("Returned error mismatch. Got %v, want %v", err, tt.invokerErr)
-			}
+			require.ErrorIs(t, err, tt.invokerErr, "Returned error should match invoker error")
 		})
 	}
 }

68-103: Consider using testify assertions for better test output.

Same as the unary test, prefer testify/require for more descriptive assertion failures.

🔎 Refactor to use testify/require
 			_, err := interceptor(context.Background(), desc, nil, tt.method, streamer)
-			if !errors.Is(err, tt.streamerErr) {
-				t.Fatalf("Returned error mismatch. Got %v, want %v", err, tt.streamerErr)
-			}
+			require.ErrorIs(t, err, tt.streamerErr, "Returned error should match streamer error")
 		})
 	}
 }
client-go/hack/overlays/client/versioned/clientset.go (1)

1-10: Missing package-level godoc comment.

Per coding guidelines, package-level godoc is required for all Go packages. Consider adding a doc comment describing this package's purpose.

+// Package versioned provides the versioned clientset for the NVIDIA Device API,
+// enabling gRPC-based access to GPU resources using Kubernetes-native patterns.
 package versioned
client-go/hack/overlays/client/versioned/integration_test.go (1)

64-86: Consider using testify for assertions.

Per coding guidelines, testify/assert and testify/require are preferred for assertions in Go tests. This would improve readability and provide better error messages.

Example refactor for Get subtest
+import (
+    "github.com/stretchr/testify/assert"
+    "github.com/stretchr/testify/require"
+)

 t.Run("Get", func(t *testing.T) {
     gpu, err := cs.DeviceV1alpha1().GPUs().Get(ctx, "gpu-1", metav1.GetOptions{})
-    if err != nil {
-        t.Fatalf("Get failed: %v", err)
-    }
-    if gpu.Name != "gpu-1" {
-        t.Errorf("Expected gpu-1, got %s", gpu.Name)
-    }
+    require.NoError(t, err, "Get failed")
+    assert.Equal(t, "gpu-1", gpu.Name)
 })
client-go/client/versioned/integration_test.go (1)

271-353: Consider extracting shared test utilities.

The mockGpuServer implementation and test patterns are nearly identical to client-go/hack/overlays/client/versioned/integration_test.go. Consider extracting the mock server and common test helpers into a shared internal test package to reduce duplication.

client-go/examples/fake-server/main.go (2)

40-41: Consider using structured logging.

Per coding guidelines, log/slog is preferred for structured logging in Go code. While simpler logging may suffice for an example server, structured logs would better demonstrate production patterns.

Example using slog
import "log/slog"

// In main()
slog.Info("Starting server")
slog.Info("Fake Device API listening", "socketPath", socketPath)

// In WatchGpus
slog.Info("Watch stream connected")
slog.Info("Watch stream disconnected")

Also applies to: 228-234


157-166: Non-blocking broadcast silently drops events.

The select/default pattern prevents deadlock but silently drops events when channels are full. This is fine for a fake server, but consider adding a debug log when events are dropped to aid troubleshooting.

 select {
 case ch <- gpu:
 default:
+    // Event dropped - listener channel full
 }
api/device/v1alpha1/gpu_types.go (1)

15-19: Missing package-level godoc comment.

Per coding guidelines, package-level godoc is required. Consider adding documentation for this API package.

+// Package v1alpha1 contains API types for the NVIDIA Device API v1alpha1 version.
+// It defines the GPU resource type and related specifications for representing
+// GPU devices in a Kubernetes-native way.
 package v1alpha1
client-go/nvgrpc/watcher.go (1)

106-121: Consider adding BOOKMARK event type support.

Kubernetes informers use BOOKMARK events for watch progress updates. If the gRPC service may send bookmark events, consider handling them:

+case "BOOKMARK":
+    eventType = watch.Bookmark
 case "ERROR":

If bookmarks aren't part of your protocol, this can be deferred.

client-go/informers/externalversions/generic.go (1)

50-50: Address the TODO comment.

The TODO indicates plans to extend generic informer support to unknown resources with a client pool. Consider tracking this as a feature request.

Do you want me to open a new issue to track this enhancement?

client-go/nvgrpc/watcher_test.go (1)

159-159: Consider removing the sleep.

The time.Sleep(10 * time.Millisecond) is used to allow the receive loop to start, but this introduces timing dependencies. Consider if synchronization primitives or test helpers could eliminate this sleep.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9b3add0 and bc160e9.

⛔ Files ignored due to path filters (3)
  • api/gen/go/device/v1alpha1/gpu.pb.go is excluded by !**/*.pb.go, !**/gen/**
  • api/go.sum is excluded by !**/*.sum
  • client-go/go.sum is excluded by !**/*.sum
📒 Files selected for processing (71)
  • .gitignore (1 hunks)
  • .versions.yaml (1 hunks)
  • api/Makefile (5 hunks)
  • api/device/v1alpha1/converter.go (1 hunks)
  • api/device/v1alpha1/doc.go (1 hunks)
  • api/device/v1alpha1/gpu_conversion.go (1 hunks)
  • api/device/v1alpha1/gpu_conversion_test.go (1 hunks)
  • api/device/v1alpha1/gpu_types.go (1 hunks)
  • api/device/v1alpha1/register.go (1 hunks)
  • api/device/v1alpha1/zz_generated.conversion.go (1 hunks)
  • api/device/v1alpha1/zz_generated.deepcopy.go (1 hunks)
  • api/go.mod (2 hunks)
  • api/hack/boilerplate.go.txt (1 hunks)
  • api/proto/device/v1alpha1/gpu.proto (4 hunks)
  • client-go/DEVELOPMENT.md (1 hunks)
  • client-go/Makefile (1 hunks)
  • client-go/README.md (1 hunks)
  • client-go/client/versioned/clientset.go (1 hunks)
  • client-go/client/versioned/fake/clientset_generated.go (1 hunks)
  • client-go/client/versioned/fake/doc.go (1 hunks)
  • client-go/client/versioned/fake/register.go (1 hunks)
  • client-go/client/versioned/integration_test.go (1 hunks)
  • client-go/client/versioned/scheme/doc.go (1 hunks)
  • client-go/client/versioned/scheme/register.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/device_client.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/doc.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/fake/doc.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_gpu.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/generated_expansion.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/gpu.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1 hunks)
  • client-go/examples/README.md (1 hunks)
  • client-go/examples/basic-client/README.md (1 hunks)
  • client-go/examples/basic-client/main.go (1 hunks)
  • client-go/examples/controller-shim/README.md (1 hunks)
  • client-go/examples/controller-shim/main.go (1 hunks)
  • client-go/examples/fake-server/README.md (1 hunks)
  • client-go/examples/fake-server/main.go (1 hunks)
  • client-go/examples/streaming-daemon/README.md (1 hunks)
  • client-go/examples/streaming-daemon/main.go (1 hunks)
  • client-go/go.mod (1 hunks)
  • client-go/hack/apply-overlays.sh (1 hunks)
  • client-go/hack/boilerplate.go.txt (1 hunks)
  • client-go/hack/boilerplate_overlay.go.txt (1 hunks)
  • client-go/hack/overlays/client/versioned/clientset.go (1 hunks)
  • client-go/hack/overlays/client/versioned/integration_test.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1 hunks)
  • client-go/informers/externalversions/device/interface.go (1 hunks)
  • client-go/informers/externalversions/device/v1alpha1/gpu.go (1 hunks)
  • client-go/informers/externalversions/device/v1alpha1/interface.go (1 hunks)
  • client-go/informers/externalversions/factory.go (1 hunks)
  • client-go/informers/externalversions/generic.go (1 hunks)
  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go (1 hunks)
  • client-go/listers/device/v1alpha1/expansion_generated.go (1 hunks)
  • client-go/listers/device/v1alpha1/gpu.go (1 hunks)
  • client-go/nvgrpc/client_conn.go (1 hunks)
  • client-go/nvgrpc/client_conn_test.go (1 hunks)
  • client-go/nvgrpc/config.go (1 hunks)
  • client-go/nvgrpc/config_test.go (1 hunks)
  • client-go/nvgrpc/interceptors.go (1 hunks)
  • client-go/nvgrpc/interceptors_test.go (1 hunks)
  • client-go/nvgrpc/options.go (1 hunks)
  • client-go/nvgrpc/options_test.go (1 hunks)
  • client-go/nvgrpc/watcher.go (1 hunks)
  • client-go/nvgrpc/watcher_test.go (1 hunks)
  • client-go/version/version.go (1 hunks)
  • client-go/version/version_test.go (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • client-go/hack/boilerplate.go.txt
  • api/hack/boilerplate.go.txt
🚧 Files skipped from review as they are similar to previous changes (30)
  • client-go/examples/basic-client/main.go
  • client-go/hack/apply-overlays.sh
  • client-go/client/versioned/scheme/register.go
  • client-go/client/versioned/fake/doc.go
  • client-go/hack/boilerplate_overlay.go.txt
  • client-go/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go
  • client-go/informers/externalversions/device/v1alpha1/gpu.go
  • client-go/nvgrpc/client_conn_test.go
  • api/device/v1alpha1/gpu_conversion_test.go
  • .gitignore
  • client-go/examples/controller-shim/README.md
  • api/go.mod
  • client-go/examples/fake-server/README.md
  • client-go/client/versioned/typed/device/v1alpha1/gpu.go
  • client-go/informers/externalversions/device/interface.go
  • client-go/informers/externalversions/device/v1alpha1/interface.go
  • client-go/version/version_test.go
  • client-go/client/versioned/clientset.go
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • api/device/v1alpha1/zz_generated.deepcopy.go
  • client-go/client/versioned/typed/device/v1alpha1/doc.go
  • client-go/nvgrpc/config.go
  • client-go/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/nvgrpc/client_conn.go
  • client-go/client/versioned/typed/device/v1alpha1/fake/doc.go
  • client-go/README.md
  • client-go/client/versioned/fake/clientset_generated.go
  • client-go/client/versioned/scheme/doc.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.go: Follow standard Go conventions with gofmt and golint
Use structured logging via log/slog in Go code
Wrap errors with context using fmt.Errorf("context: %w", err) in Go code
Within retry.RetryOnConflict blocks, return errors without wrapping to preserve retry behavior
Use meaningful variable names such as synced over ok for cache sync checks
Use client-go for Kubernetes API interactions in Go code
Prefer informers over direct API calls for watching Kubernetes resources
Implement proper shutdown handling with context cancellation in Go code
Package-level godoc required for all Go packages
Function comments required for all exported Go functions
Use inline comments for complex logic only in Go code
TODO comments should reference issues in Go code
Extract informer event handler setup into helper methods
Use separate informers for different Kubernetes resource types

Files:

  • client-go/client/versioned/typed/device/v1alpha1/generated_expansion.go
  • client-go/nvgrpc/options_test.go
  • client-go/listers/device/v1alpha1/gpu.go
  • client-go/client/versioned/fake/register.go
  • client-go/examples/streaming-daemon/main.go
  • api/device/v1alpha1/doc.go
  • api/device/v1alpha1/gpu_conversion.go
  • client-go/nvgrpc/config_test.go
  • client-go/version/version.go
  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go
  • client-go/nvgrpc/interceptors.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/hack/overlays/client/versioned/clientset.go
  • client-go/informers/externalversions/generic.go
  • api/device/v1alpha1/gpu_types.go
  • api/device/v1alpha1/converter.go
  • client-go/informers/externalversions/factory.go
  • client-go/nvgrpc/watcher_test.go
  • api/device/v1alpha1/register.go
  • client-go/listers/device/v1alpha1/expansion_generated.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/nvgrpc/watcher.go
  • client-go/examples/controller-shim/main.go
  • client-go/client/versioned/integration_test.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/nvgrpc/options.go
  • api/device/v1alpha1/zz_generated.conversion.go
  • client-go/nvgrpc/interceptors_test.go
  • client-go/examples/fake-server/main.go
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_gpu.go
**/*_test.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*_test.go: Use envtest for testing Kubernetes controllers instead of fake clients
Use testify/assert and testify/require for assertions in Go tests
Write table-driven tests when testing multiple scenarios in Go
Name Go tests descriptively using format: TestFunctionName_Scenario_ExpectedBehavior

Files:

  • client-go/nvgrpc/options_test.go
  • client-go/nvgrpc/config_test.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/nvgrpc/watcher_test.go
  • client-go/client/versioned/integration_test.go
  • client-go/nvgrpc/interceptors_test.go
**/go.mod

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use go.mod for each service as a separate Go module with semantic import versioning

Files:

  • client-go/go.mod
🧠 Learnings (15)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code

Applied to files:

  • client-go/examples/basic-client/README.md
  • client-go/version/version.go
  • client-go/go.mod
  • .versions.yaml
  • client-go/examples/README.md
  • client-go/DEVELOPMENT.md
  • client-go/Makefile
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : TODO comments should reference issues in Go code

Applied to files:

  • client-go/version/version.go
  • client-go/go.mod
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Extract informer event handler setup into helper methods

Applied to files:

  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go
  • client-go/informers/externalversions/generic.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use separate informers for different Kubernetes resource types

Applied to files:

  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go
  • client-go/informers/externalversions/generic.go
  • client-go/informers/externalversions/factory.go
  • client-go/examples/controller-shim/main.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Prefer informers over direct API calls for watching Kubernetes resources

Applied to files:

  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go
  • client-go/informers/externalversions/generic.go
  • client-go/go.mod
  • client-go/informers/externalversions/factory.go
  • client-go/nvgrpc/watcher.go
  • client-go/examples/controller-shim/main.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Use `envtest` for testing Kubernetes controllers instead of fake clients

Applied to files:

  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/go.mod
  • .versions.yaml
  • client-go/examples/README.md
  • client-go/nvgrpc/watcher_test.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use meaningful variable names such as `synced` over `ok` for cache sync checks

Applied to files:

  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Implement proper shutdown handling with context cancellation in Go code

Applied to files:

  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/informers/externalversions/factory.go
  • client-go/nvgrpc/watcher.go
  • client-go/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/go.mod : Use `go.mod` for each service as a separate Go module with semantic import versioning

Applied to files:

  • client-go/go.mod
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Keep Go dependencies minimal and up-to-date

Applied to files:

  • client-go/go.mod
  • .versions.yaml
  • api/Makefile
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to data-models/protobufs/**/*.proto : Include comprehensive comments for all fields in Protocol Buffer messages

Applied to files:

  • api/proto/device/v1alpha1/gpu.proto
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to data-models/protobufs/**/*.proto : Use semantic versioning for breaking changes in Protocol Buffer messages

Applied to files:

  • api/proto/device/v1alpha1/gpu.proto
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Use `testify/assert` and `testify/require` for assertions in Go tests

Applied to files:

  • client-go/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Write table-driven tests when testing multiple scenarios in Go

Applied to files:

  • client-go/client/versioned/integration_test.go
🧬 Code graph analysis (12)
client-go/nvgrpc/options_test.go (1)
client-go/nvgrpc/options.go (4)
  • DialOption (23-23)
  • WithLogger (32-36)
  • WithUnaryInterceptor (39-43)
  • WithStreamInterceptor (46-50)
client-go/listers/device/v1alpha1/gpu.go (3)
api/device/v1alpha1/gpu_types.go (1)
  • GPU (55-61)
client-go/listers/device/v1alpha1/expansion_generated.go (1)
  • GPUListerExpansion (21-21)
api/device/v1alpha1/register.go (1)
  • Resource (25-27)
client-go/client/versioned/fake/register.go (2)
api/device/v1alpha1/register.go (2)
  • SchemeBuilder (31-31)
  • AddToScheme (34-34)
client-go/client/versioned/scheme/register.go (1)
  • AddToScheme (49-49)
client-go/nvgrpc/config_test.go (2)
client-go/nvgrpc/config.go (3)
  • DefaultNvidiaDeviceAPISocket (31-31)
  • NvidiaDeviceAPITargetEnvVar (28-28)
  • Config (41-49)
client-go/version/version.go (1)
  • UserAgent (28-35)
api/device/v1alpha1/converter.go (3)
api/gen/go/device/v1alpha1/gpu.pb.go (21)
  • Gpu (159-169)
  • Gpu (182-182)
  • Gpu (197-199)
  • GpuList (223-230)
  • GpuList (243-243)
  • GpuList (258-260)
  • ObjectMeta (40-53)
  • ObjectMeta (66-66)
  • ObjectMeta (81-83)
  • ListMeta (100-112)
  • ListMeta (125-125)
  • ListMeta (140-142)
  • GpuSpec (277-285)
  • GpuSpec (298-298)
  • GpuSpec (313-315)
  • GpuStatus (325-333)
  • GpuStatus (346-346)
  • GpuStatus (361-363)
  • Condition (380-398)
  • Condition (411-411)
  • Condition (426-428)
api/device/v1alpha1/gpu_types.go (3)
  • GPU (55-61)
  • GPUSpec (24-30)
  • GPUStatus (35-45)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
client-go/nvgrpc/watcher_test.go (1)
client-go/nvgrpc/watcher.go (1)
  • NewWatcher (47-62)
api/device/v1alpha1/register.go (3)
client-go/client/versioned/fake/register.go (1)
  • AddToScheme (49-49)
client-go/client/versioned/scheme/register.go (2)
  • AddToScheme (49-49)
  • Scheme (28-28)
api/device/v1alpha1/gpu_types.go (2)
  • GPU (55-61)
  • GPUList (67-71)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (2)
client-go/client/versioned/typed/device/v1alpha1/gpu.go (1)
  • GPUInterface (38-43)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (1)
  • GPUInterface (22-27)
client-go/examples/controller-shim/main.go (9)
client-go/client/versioned/clientset.go (1)
  • New (95-99)
client-go/client/versioned/typed/device/v1alpha1/device_client.go (1)
  • New (74-79)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1)
  • New (58-63)
client-go/informers/externalversions/device/interface.go (1)
  • New (37-39)
client-go/informers/externalversions/device/v1alpha1/interface.go (1)
  • New (36-38)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/informers/externalversions/factory.go (1)
  • NewSharedInformerFactory (91-93)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
api/device/v1alpha1/gpu_types.go (1)
  • GPU (55-61)
client-go/nvgrpc/interceptors_test.go (1)
client-go/nvgrpc/interceptors.go (2)
  • NewLatencyUnaryInterceptor (28-59)
  • NewLatencyStreamInterceptor (62-92)
client-go/examples/fake-server/main.go (3)
api/device/v1alpha1/gpu_types.go (3)
  • GPU (55-61)
  • GPUSpec (24-30)
  • GPUStatus (35-45)
api/gen/go/device/v1alpha1/gpu.pb.go (12)
  • ObjectMeta (40-53)
  • ObjectMeta (66-66)
  • ObjectMeta (81-83)
  • Condition (380-398)
  • Condition (411-411)
  • Condition (426-428)
  • Gpu (159-169)
  • Gpu (182-182)
  • Gpu (197-199)
  • WatchGpusResponse (696-713)
  • WatchGpusResponse (726-726)
  • WatchGpusResponse (741-743)
api/device/v1alpha1/gpu_conversion.go (1)
  • ToProto (35-40)
client-go/client/versioned/typed/device/v1alpha1/fake/fake_gpu.go (7)
api/device/v1alpha1/gpu_types.go (2)
  • GPU (55-61)
  • GPUList (67-71)
client-go/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1)
  • FakeDeviceV1alpha1 (25-27)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1)
  • FakeDeviceV1alpha1 (9-11)
client-go/client/versioned/typed/device/v1alpha1/gpu.go (1)
  • GPUInterface (38-43)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (1)
  • GPUInterface (22-27)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
api/gen/go/device/v1alpha1/gpu.pb.go (3)
  • ListMeta (100-112)
  • ListMeta (125-125)
  • ListMeta (140-142)
🪛 checkmake (0.2.2)
client-go/Makefile

[warning] 187-187: Target "tools" should be declared PHONY.

(phonydeclared)

🪛 LanguageTool
client-go/DEVELOPMENT.md

[style] ~77-~77: This phrase is redundant. Consider using “inside”.
Context: ... informers/) The directory structure inside of hack/overlays/ *must exactly mirror...

(OUTSIDE_OF)

🪛 markdownlint-cli2 (0.18.1)
client-go/DEVELOPMENT.md

10-10: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


11-11: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)

🔇 Additional comments (52)
client-go/client/versioned/typed/device/v1alpha1/generated_expansion.go (1)

1-19: LGTM!

Standard client-gen expansion interface pattern. The empty GPUExpansion interface provides an extension point for custom methods without modifying generated code.

client-go/client/versioned/typed/device/v1alpha1/fake/fake_gpu.go (1)

25-46: LGTM!

Generated fake client correctly implements GPUInterface using gentype.FakeClientWithList. The resource metadata (gpus, GPU kind) aligns with the API definitions, and the list/pointer conversion helpers follow the standard client-gen patterns.

client-go/examples/controller-shim/main.go (2)

40-56: LGTM on client initialization.

The gRPC-backed clientset setup follows the established patterns. Environment variable fallback for the target endpoint and proper error handling are implemented correctly. As per coding guidelines, client-go is used appropriately for Kubernetes API interactions.


120-142: LGTM on GPUReconciler implementation.

The reconciler follows best practices:

  • Uses client.IgnoreNotFound for graceful handling of deleted resources.
  • Structured logging via ctrl.LoggerFrom(ctx).
  • SetupWithManager is properly extracted as a helper method per coding guidelines.
api/device/v1alpha1/doc.go (1)

1-19: LGTM!

The package documentation and Kubebuilder annotation are properly structured for code generation. The +groupName marker correctly identifies the API group.

client-go/listers/device/v1alpha1/expansion_generated.go (1)

19-21: LGTM!

Standard Kubernetes code-generator expansion pattern. The empty GPUListerExpansion interface enables downstream augmentation of GPULister without modifying generated code.

client-go/client/versioned/fake/register.go (1)

28-54: LGTM!

The fake scheme registration follows standard Kubernetes client-go patterns. The initialization sequence correctly registers metav1 core types and device.nvidia.com/v1alpha1 types into the fake clientset's scheme.

api/device/v1alpha1/register.go (1)

23-44: LGTM!

The API registration correctly follows Kubernetes conventions. The SchemeGroupVersion, SchemeBuilder, and addKnownTypes properly register GPU and GPUList types for the device.nvidia.com/v1alpha1 group.

client-go/examples/streaming-daemon/main.go (4)

36-45: LGTM!

Logger initialization and environment-based configuration are appropriate for an example program.


47-58: LGTM!

Custom interceptors effectively demonstrate how to extend gRPC client behavior with metadata injection and logging.


60-94: LGTM!

Client initialization and List operation demonstrate proper error handling, resource cleanup with defer, and timeout management.


96-143: LGTM! Example demonstrates watch stream patterns well.

The watch implementation shows proper error handling, type assertions, and timeout management. For production use, consider adding signal handling (SIGTERM/SIGINT) for graceful shutdown, but this is appropriate for an example program.

client-go/listers/device/v1alpha1/gpu.go (1)

26-46: LGTM!

Generated lister code follows standard Kubernetes client-gen patterns and correctly integrates with the GPU resource type.

client-go/nvgrpc/interceptors.go (2)

27-59: LGTM!

Interceptor correctly measures latency, applies appropriate log levels based on error types, and preserves original error propagation.


61-92: LGTM!

Stream interceptor follows consistent patterns with the unary interceptor and correctly handles stream establishment latency tracking.

api/device/v1alpha1/gpu_conversion.go (4)

24-32: LGTM!

Proper nil handling and delegation to the generated converter implementation.


34-40: LGTM!

Correct nil handling and dereferencing for the protobuf conversion.


42-48: LGTM!

Proper nil handling for list conversion.


50-56: LGTM!

Correct nil handling and dereferencing for list conversion.

client-go/informers/externalversions/internalinterfaces/factory_interfaces.go (1)

28-38: LGTM!

Generated informer interfaces follow standard Kubernetes informer-gen patterns and align with retrieved learnings about informer usage.

Based on learnings, these interfaces support the pattern of using informers over direct API calls and enable proper informer factory management.

client-go/nvgrpc/options.go (2)

22-29: LGTM!

Functional options pattern is correctly implemented with an unexported options struct and exported option type.


31-50: LGTM!

Option configurators correctly implement composition for interceptors (append) and replacement for logger (assignment), which is the expected behavior for these types of options.

api/proto/device/v1alpha1/gpu.proto (2)

53-70: LGTM!

Gpu message structure follows Kubernetes resource patterns with proper metadata, spec, and status separation. Field numbering is stable and comments are comprehensive.


72-167: LGTM! Metadata additions enable Kubernetes-native semantics.

The addition of ListMeta and resource_version fields to GpuList, ListGpusRequest, and WatchGpusRequest enables versioned listing and watch operations consistent with Kubernetes API patterns. The breaking change to GpuList field numbering (items from 1→2) is appropriately flagged in the PR objectives.

client-go/hack/overlays/client/versioned/clientset.go (1)

26-83: LGTM!

The constructor functions follow standard client-go patterns with proper nil validation, defensive shallow copying to prevent config mutation, and clear error messages. The NewForConfigOrDie pattern matches Kubernetes conventions.

client-go/hack/overlays/client/versioned/integration_test.go (1)

257-337: LGTM!

The mock server implementation is well-structured with proper thread-safety via sync.RWMutex, clean context cancellation handling in WatchGpus, and an appropriate channel-based event delivery mechanism for testing watch flows.

client-go/examples/fake-server/main.go (1)

68-76: LGTM for signal handling.

The graceful shutdown handling correctly stops the gRPC server and cleans up the socket file on SIGINT/SIGTERM.

api/device/v1alpha1/gpu_types.go (1)

47-61: LGTM!

The GPU type is well-defined with proper Kubernetes API conventions. The genclient markers correctly indicate this is a cluster-scoped, read-only resource with get/list/watch verbs, which aligns with the PR's goal of exposing GPU state without mutation capabilities.

client-go/nvgrpc/watcher.go (1)

139-163: LGTM!

The error-to-status mapping correctly translates gRPC error codes to Kubernetes status responses. The special handling for OutOfRange and ResourceExhausted → 410 Expired is critical for triggering informer relist behavior, and the inline comment documents this well.

api/device/v1alpha1/converter.go (2)

23-104: LGTM!

The Converter interface is well-structured with comprehensive goverter annotations. The bidirectional mappings between protobuf and Kubernetes types are complete, and the goverter:ignore directives appropriately handle Kubernetes-specific fields not present in the protobuf definitions.


122-133: LGTM!

The timestamp conversion helpers correctly handle nil protobuf timestamps and properly convert between metav1.Time and timestamppb.Timestamp.

client-go/informers/externalversions/generic.go (2)

27-37: LGTM!

The GenericInformer interface and genericInformer struct follow standard client-go patterns for generic informer access.


39-47: LGTM!

The Informer and Lister methods correctly implement the GenericInformer interface using standard client-go patterns.

client-go/nvgrpc/watcher_test.go (5)

31-58: LGTM!

The test correctly validates the normal event flow (ADDED, MODIFIED, DELETED) and verifies event types.


60-83: LGTM!

The test correctly validates that UNKNOWN event types are ignored and subsequent ADDED events are processed.


85-117: LGTM!

The table-driven test correctly validates error propagation and metav1.Status formatting for different gRPC error codes.


119-151: LGTM!

The test correctly validates that errors terminate the stream and includes appropriate timeout handling to prevent test hangs.


178-238: LGTM!

The test helpers (FakeObject, FakeSource) are well-implemented with proper nil-safety, idempotent Close(), and correct runtime.Object implementation.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (5)

9-18: LGTM!

The DeviceV1alpha1Interface and DeviceV1alpha1Client follow standard client-go patterns for versioned clients.


20-22: LGTM!

The GPUs() method correctly returns a GPUInterface using the standard factory pattern.


24-35: LGTM!

The NewForConfig constructor correctly creates a shallow copy of the config to prevent mutation and properly handles errors.


37-55: LGTM!

The constructors follow standard Kubernetes client patterns, with NewForConfigOrDie appropriately using panic for fatal configuration errors.


57-73: LGTM!

The New() constructor appropriately uses a discarded logger, and ClientConn() includes proper nil-safety checks.

api/device/v1alpha1/zz_generated.conversion.go (2)

11-84: LGTM!

The FromProtobuf* conversion methods correctly implement nil-safety and proper slice handling for conversions from protobuf to internal Go types.


85-142: LGTM!

The ToProtobuf* conversion methods correctly implement conversions from internal Go types to protobuf, with appropriate nil-safety for pointer receivers.

client-go/informers/externalversions/factory.go (7)

33-88: LGTM!

The functional options (WithCustomResyncConfig, WithTweakListOptions, WithNamespace, WithTransform) follow the standard functional options pattern correctly.


90-120: LGTM!

The factory constructors are correctly implemented, with appropriate deprecation notices and functional option application.


122-144: LGTM!

The Start method correctly implements safe multi-call semantics with proper loop variable capture, WaitGroup tracking, and shutdown flag checking.


146-153: LGTM!

The Shutdown method correctly sets the shutdown flag under lock and waits for all goroutines to complete.


155-174: LGTM!

WaitForCacheSync correctly minimizes lock contention by copying the informers map and only waits for informers that have been started.


176-198: LGTM!

InformerFor correctly implements lazy initialization with proper locking, per-type resync configuration, and transform application.


258-260: LGTM!

The Device() method correctly returns a device.Interface with appropriate namespace and tweak options.

Copy link
Contributor

@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: 4

♻️ Duplicate comments (9)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (2)

1-1: Add package-level godoc comment.

The coding guidelines require package-level documentation for all Go packages. A past review comment already flagged this missing documentation.

As per coding guidelines.

🔎 Suggested documentation
+// Package fake provides fake implementations of the device v1alpha1 client
+// for testing purposes. These fakes use an in-memory ObjectTracker instead
+// of actual gRPC connections.
 package fake

13-15: Add function comment for exported method.

The coding guidelines require function comments for all exported Go functions. A past review comment already flagged this missing documentation.

As per coding guidelines.

🔎 Suggested documentation
+// GPUs returns a fake GPUInterface for testing GPU operations
+// without requiring an actual gRPC connection.
 func (c *FakeDeviceV1alpha1) GPUs() v1alpha1.GPUInterface {
 	return newFakeGPUs(c)
 }
api/proto/device/v1alpha1/gpu.proto (1)

27-51: Metadata types align with Kubernetes conventions.

The ObjectMeta and ListMeta messages follow Kubernetes API patterns correctly, with appropriate field documentation explaining the opaque, read-only nature of resource_version.

Note: The indentation inconsistency in comments (lines 35-37, 47-48) has already been flagged in a previous review.

client-go/hack/overlays/client/versioned/integration_test.go (1)

210-214: Avoid calling t.Errorf from a goroutine.

As previously noted, calling t.Errorf (or any t method) from a goroutine is unsafe and can cause race conditions. Use an error channel to communicate errors back to the main test goroutine.

client-go/examples/controller-shim/main.go (1)

58-62: The informer factory is never started.

The comment on Line 60 states the Manager will start the injected informer, but controller-runtime only starts informers created through its own cache machinery. The gRPC-backed informer from factory needs to be started explicitly; otherwise, the cache will never populate and reconciliation won't occur.

🔎 Proposed fix

Start the factory before starting the manager:

 	factory := informers.NewSharedInformerFactory(clientset, 10*time.Minute)
 	gpuInformer := factory.Device().V1alpha1().GPUs().Informer()
+
+	// Start the factory to populate the gRPC-backed informer cache.
+	// The manager's lifecycle context will handle shutdown.
+	ctx := ctrl.SetupSignalHandler()
+	go factory.Start(ctx.Done())
+
+	// Wait for the informer cache to sync before starting the manager.
+	if !cache.WaitForCacheSync(ctx.Done(), gpuInformer.HasSynced) {
+		setupLog.Error(nil, "failed to sync informer cache")
+		os.Exit(1)
+	}

 	// Initialize the controller-runtime Manager.

Then update the manager initialization to use the already-created ctx:

-	ctx := ctrl.SetupSignalHandler()
-
 	setupLog.Info("starting manager")
 	if err := mgr.Start(ctx); err != nil {
client-go/client/versioned/integration_test.go (2)

15-15: Misleading "DO NOT EDIT" header for a manually maintained test file.

This test file contains substantial manual test logic (mock server, test cases, assertions). The "Code generated... DO NOT EDIT" comment may confuse maintainers about whether modifications are allowed.

🔎 Proposed fix

Replace with a clear header:

-// Code generated by client-gen and gRPC overlay. DO NOT EDIT.
+// Integration test - manually maintained. Changes permitted.

226-230: Goroutine error won't fail the test reliably.

t.Errorf called from within a goroutine will log the error but won't cause the test to fail properly since the goroutine runs concurrently. Consider using a channel or errgroup to propagate failures.

🔎 Proposed fix using errgroup
+import "golang.org/x/sync/errgroup"
+
 	factory.Start(stopCh)
-	go func() {
-		if err := c.Start(ctx); err != nil {
-			t.Errorf("Cache failed to start: %v", err)
-		}
-	}()
+
+	var eg errgroup.Group
+	eg.Go(func() error {
+		return c.Start(ctx)
+	})
+	defer func() {
+		if err := eg.Wait(); err != nil && ctx.Err() == nil {
+			t.Fatalf("Cache failed to start: %v", err)
+		}
+	}()
client-go/informers/externalversions/device/v1alpha1/gpu.go (1)

89-91: Remove NamespaceIndex from GPU informer—GPU is a cluster-scoped resource.

GPU is explicitly marked as +genclient:nonNamespaced, making it a cluster-scoped resource. The defaultInformer should not use cache.NamespaceIndex: cache.MetaNamespaceIndexFunc since cluster-scoped resources have no namespace semantics.

🔎 Proposed fix

Remove the namespace indexer:

 func (f *gPUInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
-	return NewFilteredGPUInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
+	return NewFilteredGPUInformer(client, resyncPeriod, cache.Indexers{}, f.tweakListOptions)
 }
client-go/examples/fake-server/main.go (1)

185-193: ListMeta is not populated in the response.

The GpuList response doesn't include metadata.resource_version, which is needed for clients to establish a watch from a consistent point (List-then-Watch pattern). Consider adding a list-level resource version.

🔎 Proposed fix

Track a server-level resource version and populate ListMeta:

+type fakeServer struct {
+	pb.UnimplementedGpuServiceServer
+	mu               sync.RWMutex
+	gpus             []devicev1alpha1.GPU
+	listeners        map[chan struct{}]chan devicev1alpha1.GPU
+	resourceVersion  int64  // Track global resource version
+}

 func (s *fakeServer) ListGpus(ctx context.Context, req *pb.ListGpusRequest) (*pb.ListGpusResponse, error) {
 	s.mu.RLock()
 	defer s.mu.RUnlock()

 	gpuList := &pb.GpuList{
+		Metadata: &pb.ListMeta{
+			ResourceVersion: strconv.FormatInt(s.resourceVersion, 10),
+		},
 		Items: make([]*pb.Gpu, 0, len(s.gpus)),
 	}
🧹 Nitpick comments (7)
client-go/version/version_test.go (1)

16-18: Consider using testify/assert for assertions.

The coding guidelines recommend using testify/assert or testify/require for test assertions.

As per coding guidelines, prefer testify assertions:

🔎 Proposed refactor using testify/assert

Add the import:

import (
	"fmt"
	"runtime"
	"testing"

	"github.com/stretchr/testify/assert"
)

Then refactor the assertion:

 	expected := fmt.Sprintf("nvidia-device-api-client/v1.2.3-test (%s/%s)", runtime.GOOS, runtime.GOARCH)
-	if got := UserAgent(); got != expected {
-		t.Errorf("UserAgent() = %q, want %q", got, expected)
-	}
+	assert.Equal(t, expected, UserAgent())
client-go/DEVELOPMENT.md (2)

10-11: Optional: Adjust list indentation for consistency.

Static analysis detected that the nested list items use 4-space indentation instead of the standard 2-space indentation for Markdown.

🔎 Suggested fix
 * **yq**: Required to parse version configuration.
-    * *macOS*: `brew install yq`
-    * *Linux*: See [yq installation](https://github.com/mikefarah/yq)
+  * *macOS*: `brew install yq`
+  * *Linux*: See [yq installation](https://github.com/mikefarah/yq)

77-77: Optional: Simplify phrase for clarity.

The phrase "inside of" can be simplified to "inside" for more concise writing.

🔎 Suggested fix
-The directory structure inside of `hack/overlays/` **must exactly mirror** the structure of the generated code.
+The directory structure inside `hack/overlays/` **must exactly mirror** the structure of the generated code.
client-go/nvgrpc/options.go (1)

31-36: Godoc comment could be more descriptive.

While the function has a comment, it could better explain when and why you'd use this option.

As per coding guidelines.

🔎 Enhanced documentation
-// WithLogger sets the logger to be used by the client.
+// WithLogger configures the logger for client operations and interceptors.
+// If not provided, the client will use a discard logger.
 func WithLogger(logger logr.Logger) DialOption {
client-go/nvgrpc/config.go (1)

30-31: Default socket path differs from examples.

The default socket path is unix:///var/run/nvidia-device-api/device-api.sock, but examples (e.g., controller-shim/main.go line 47 and fake-server/main.go line 46) use unix:///tmp/nvidia-device-api.sock. This inconsistency may confuse users.

Consider documenting why the paths differ (production vs. dev/test) or standardizing them for consistency across examples.

client-go/client/versioned/typed/device/v1alpha1/device_client.go (1)

53-60: Consider simplifying the error return.

NewForConfigAndClient always returns a nil error, though the function signature includes an error return. This appears to be for consistency with the parent Clientset pattern (see client/versioned/clientset.go). While this provides API uniformity and future-proofing, if no validation or error conditions are anticipated, the signature could be simplified to not return an error.

client-go/Makefile (1)

105-113: Verify that excluding examples from build is intentional.

The build target excludes examples/ from compilation (line 108), which means compilation issues in example code won't be detected by CI. While this may be intentional to keep the main build fast, consider adding a separate build-examples target or including examples in CI to ensure they remain functional as the API evolves.

🔎 Optional: Add separate target for examples
 .PHONY: build
 build: code-gen ## Compile all Go code after generation to verify type safety.
 	@echo "Compiling..."
 	go build -v $(LDFLAGS) $$(go list ./... | grep -vE '/hack/overlays/|/examples/')

+.PHONY: build-examples
+build-examples: code-gen ## Compile example code to verify examples stay current.
+	@echo "Compiling examples..."
+	go build -v $(LDFLAGS) ./examples/...
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bc160e9 and 1776d86.

⛔ Files ignored due to path filters (3)
  • api/gen/go/device/v1alpha1/gpu.pb.go is excluded by !**/*.pb.go, !**/gen/**
  • api/go.sum is excluded by !**/*.sum
  • client-go/go.sum is excluded by !**/*.sum
📒 Files selected for processing (71)
  • .gitignore (1 hunks)
  • .versions.yaml (1 hunks)
  • api/Makefile (5 hunks)
  • api/device/v1alpha1/converter.go (1 hunks)
  • api/device/v1alpha1/doc.go (1 hunks)
  • api/device/v1alpha1/gpu_conversion.go (1 hunks)
  • api/device/v1alpha1/gpu_conversion_test.go (1 hunks)
  • api/device/v1alpha1/gpu_types.go (1 hunks)
  • api/device/v1alpha1/register.go (1 hunks)
  • api/device/v1alpha1/zz_generated.conversion.go (1 hunks)
  • api/device/v1alpha1/zz_generated.deepcopy.go (1 hunks)
  • api/go.mod (2 hunks)
  • api/hack/boilerplate.go.txt (1 hunks)
  • api/proto/device/v1alpha1/gpu.proto (4 hunks)
  • client-go/DEVELOPMENT.md (1 hunks)
  • client-go/Makefile (1 hunks)
  • client-go/README.md (1 hunks)
  • client-go/client/versioned/clientset.go (1 hunks)
  • client-go/client/versioned/fake/clientset_generated.go (1 hunks)
  • client-go/client/versioned/fake/doc.go (1 hunks)
  • client-go/client/versioned/fake/register.go (1 hunks)
  • client-go/client/versioned/integration_test.go (1 hunks)
  • client-go/client/versioned/scheme/doc.go (1 hunks)
  • client-go/client/versioned/scheme/register.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/device_client.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/doc.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/fake/doc.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_gpu.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/generated_expansion.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/gpu.go (1 hunks)
  • client-go/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1 hunks)
  • client-go/examples/README.md (1 hunks)
  • client-go/examples/basic-client/README.md (1 hunks)
  • client-go/examples/basic-client/main.go (1 hunks)
  • client-go/examples/controller-shim/README.md (1 hunks)
  • client-go/examples/controller-shim/main.go (1 hunks)
  • client-go/examples/fake-server/README.md (1 hunks)
  • client-go/examples/fake-server/main.go (1 hunks)
  • client-go/examples/streaming-daemon/README.md (1 hunks)
  • client-go/examples/streaming-daemon/main.go (1 hunks)
  • client-go/go.mod (1 hunks)
  • client-go/hack/apply-overlays.sh (1 hunks)
  • client-go/hack/boilerplate.go.txt (1 hunks)
  • client-go/hack/boilerplate_overlay.go.txt (1 hunks)
  • client-go/hack/overlays/client/versioned/clientset.go (1 hunks)
  • client-go/hack/overlays/client/versioned/integration_test.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1 hunks)
  • client-go/informers/externalversions/device/interface.go (1 hunks)
  • client-go/informers/externalversions/device/v1alpha1/gpu.go (1 hunks)
  • client-go/informers/externalversions/device/v1alpha1/interface.go (1 hunks)
  • client-go/informers/externalversions/factory.go (1 hunks)
  • client-go/informers/externalversions/generic.go (1 hunks)
  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go (1 hunks)
  • client-go/listers/device/v1alpha1/expansion_generated.go (1 hunks)
  • client-go/listers/device/v1alpha1/gpu.go (1 hunks)
  • client-go/nvgrpc/client_conn.go (1 hunks)
  • client-go/nvgrpc/client_conn_test.go (1 hunks)
  • client-go/nvgrpc/config.go (1 hunks)
  • client-go/nvgrpc/config_test.go (1 hunks)
  • client-go/nvgrpc/interceptors.go (1 hunks)
  • client-go/nvgrpc/interceptors_test.go (1 hunks)
  • client-go/nvgrpc/options.go (1 hunks)
  • client-go/nvgrpc/options_test.go (1 hunks)
  • client-go/nvgrpc/watcher.go (1 hunks)
  • client-go/nvgrpc/watcher_test.go (1 hunks)
  • client-go/version/version.go (1 hunks)
  • client-go/version/version_test.go (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • api/hack/boilerplate.go.txt
🚧 Files skipped from review as they are similar to previous changes (31)
  • client-go/client/versioned/fake/doc.go
  • client-go/hack/apply-overlays.sh
  • client-go/examples/basic-client/main.go
  • client-go/nvgrpc/client_conn_test.go
  • client-go/go.mod
  • client-go/examples/streaming-daemon/README.md
  • .gitignore
  • client-go/informers/externalversions/generic.go
  • client-go/nvgrpc/client_conn.go
  • client-go/examples/controller-shim/README.md
  • api/device/v1alpha1/register.go
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • api/device/v1alpha1/doc.go
  • api/device/v1alpha1/gpu_conversion_test.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go
  • client-go/informers/externalversions/device/interface.go
  • api/device/v1alpha1/converter.go
  • client-go/client/versioned/fake/register.go
  • client-go/version/version.go
  • api/device/v1alpha1/zz_generated.deepcopy.go
  • client-go/client/versioned/typed/device/v1alpha1/generated_expansion.go
  • client-go/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_gpu.go
  • .versions.yaml
  • client-go/examples/basic-client/README.md
  • client-go/nvgrpc/watcher_test.go
  • client-go/client/versioned/fake/clientset_generated.go
  • client-go/nvgrpc/interceptors_test.go
  • client-go/informers/externalversions/device/v1alpha1/interface.go
  • client-go/nvgrpc/options_test.go
  • client-go/informers/externalversions/factory.go
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.go: Follow standard Go conventions with gofmt and golint
Use structured logging via log/slog in Go code
Wrap errors with context using fmt.Errorf("context: %w", err) in Go code
Within retry.RetryOnConflict blocks, return errors without wrapping to preserve retry behavior
Use meaningful variable names such as synced over ok for cache sync checks
Use client-go for Kubernetes API interactions in Go code
Prefer informers over direct API calls for watching Kubernetes resources
Implement proper shutdown handling with context cancellation in Go code
Package-level godoc required for all Go packages
Function comments required for all exported Go functions
Use inline comments for complex logic only in Go code
TODO comments should reference issues in Go code
Extract informer event handler setup into helper methods
Use separate informers for different Kubernetes resource types

Files:

  • client-go/version/version_test.go
  • client-go/client/versioned/typed/device/v1alpha1/gpu.go
  • client-go/examples/streaming-daemon/main.go
  • client-go/hack/overlays/client/versioned/clientset.go
  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go
  • client-go/nvgrpc/config_test.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/listers/device/v1alpha1/expansion_generated.go
  • api/device/v1alpha1/gpu_conversion.go
  • client-go/client/versioned/typed/device/v1alpha1/fake/doc.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go
  • client-go/nvgrpc/options.go
  • client-go/client/versioned/scheme/register.go
  • client-go/client/versioned/integration_test.go
  • client-go/nvgrpc/watcher.go
  • client-go/client/versioned/clientset.go
  • client-go/nvgrpc/config.go
  • client-go/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/nvgrpc/interceptors.go
  • client-go/client/versioned/scheme/doc.go
  • client-go/examples/fake-server/main.go
  • client-go/informers/externalversions/device/v1alpha1/gpu.go
  • client-go/client/versioned/typed/device/v1alpha1/doc.go
  • client-go/examples/controller-shim/main.go
  • client-go/listers/device/v1alpha1/gpu.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • api/device/v1alpha1/zz_generated.conversion.go
  • api/device/v1alpha1/gpu_types.go
**/*_test.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*_test.go: Use envtest for testing Kubernetes controllers instead of fake clients
Use testify/assert and testify/require for assertions in Go tests
Write table-driven tests when testing multiple scenarios in Go
Name Go tests descriptively using format: TestFunctionName_Scenario_ExpectedBehavior

Files:

  • client-go/version/version_test.go
  • client-go/nvgrpc/config_test.go
  • client-go/client/versioned/integration_test.go
  • client-go/hack/overlays/client/versioned/integration_test.go
**/go.mod

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use go.mod for each service as a separate Go module with semantic import versioning

Files:

  • api/go.mod
🧠 Learnings (19)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Extract informer event handler setup into helper methods

Applied to files:

  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use separate informers for different Kubernetes resource types

Applied to files:

  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go
  • client-go/nvgrpc/watcher.go
  • client-go/informers/externalversions/device/v1alpha1/gpu.go
  • client-go/examples/controller-shim/main.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Prefer informers over direct API calls for watching Kubernetes resources

Applied to files:

  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go
  • api/go.mod
  • client-go/nvgrpc/watcher.go
  • client-go/informers/externalversions/device/v1alpha1/gpu.go
  • client-go/examples/controller-shim/main.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Keep Go dependencies minimal and up-to-date

Applied to files:

  • api/go.mod
  • api/Makefile
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/go.mod : Use `go.mod` for each service as a separate Go module with semantic import versioning

Applied to files:

  • api/go.mod
📚 Learning: 2025-12-01T17:53:20.067Z
Learnt from: jtschelling
Repo: NVIDIA/NVSentinel PR: 455
File: docs/designs/013-remediation-plugins.md:162-204
Timestamp: 2025-12-01T17:53:20.067Z
Learning: Code examples in design documents (docs/designs/) in the NVSentinel repository are illustrative stubs meant to show intent and architectural concepts, and do not need to be 100% correct or complete implementations (e.g., undefined variables, missing error handling, incomplete struct initialization are acceptable).

Applied to files:

  • api/go.mod
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code

Applied to files:

  • api/go.mod
  • client-go/client/versioned/scheme/register.go
  • client-go/nvgrpc/watcher.go
  • client-go/README.md
  • client-go/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/client/versioned/scheme/doc.go
  • client-go/client/versioned/typed/device/v1alpha1/doc.go
  • client-go/examples/README.md
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • api/Makefile
  • client-go/Makefile
  • client-go/hack/boilerplate_overlay.go.txt
  • client-go/DEVELOPMENT.md
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Function comments required for all exported Go functions

Applied to files:

  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Package-level godoc required for all Go packages

Applied to files:

  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/client/versioned/typed/device/v1alpha1/doc.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Use `envtest` for testing Kubernetes controllers instead of fake clients

Applied to files:

  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/client/versioned/typed/device/v1alpha1/fake/doc.go
  • client-go/client/versioned/integration_test.go
  • client-go/examples/README.md
  • client-go/hack/overlays/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : TODO comments should reference issues in Go code

Applied to files:

  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/examples/README.md
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use meaningful variable names such as `synced` over `ok` for cache sync checks

Applied to files:

  • client-go/client/versioned/integration_test.go
  • client-go/hack/overlays/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Implement proper shutdown handling with context cancellation in Go code

Applied to files:

  • client-go/client/versioned/integration_test.go
  • client-go/nvgrpc/watcher.go
  • client-go/hack/overlays/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Use `testify/assert` and `testify/require` for assertions in Go tests

Applied to files:

  • client-go/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Write table-driven tests when testing multiple scenarios in Go

Applied to files:

  • client-go/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: All files must include Apache 2.0 license header

Applied to files:

  • client-go/hack/boilerplate.go.txt
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to data-models/protobufs/**/*.proto : Include comprehensive comments for all fields in Protocol Buffer messages

Applied to files:

  • api/proto/device/v1alpha1/gpu.proto
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to data-models/protobufs/**/*.proto : Use semantic versioning for breaking changes in Protocol Buffer messages

Applied to files:

  • api/proto/device/v1alpha1/gpu.proto
🧬 Code graph analysis (12)
client-go/hack/overlays/client/versioned/clientset.go (3)
client-go/client/versioned/typed/device/v1alpha1/device_client.go (5)
  • DeviceV1alpha1Client (31-34)
  • NewForConfig (43-51)
  • NewForConfigAndClient (55-60)
  • NewForConfigOrDie (64-71)
  • New (74-79)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/nvgrpc/client_conn.go (1)
  • ClientConnFor (26-72)
client-go/informers/externalversions/internalinterfaces/factory_interfaces.go (5)
client-go/client/versioned/clientset.go (1)
  • Interface (28-30)
client-go/hack/overlays/client/versioned/clientset.go (1)
  • Interface (12-14)
client-go/informers/externalversions/device/interface.go (1)
  • Interface (25-28)
client-go/informers/externalversions/device/v1alpha1/interface.go (1)
  • Interface (24-27)
node-drainer/pkg/config/config.go (1)
  • Duration (37-39)
client-go/nvgrpc/config_test.go (2)
client-go/nvgrpc/config.go (3)
  • DefaultNvidiaDeviceAPISocket (31-31)
  • NvidiaDeviceAPITargetEnvVar (28-28)
  • Config (41-49)
client-go/version/version.go (1)
  • UserAgent (28-35)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (2)
client-go/client/versioned/typed/device/v1alpha1/gpu.go (1)
  • GPUInterface (38-43)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (1)
  • GPUInterface (22-27)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (2)
api/gen/go/device/v1alpha1/gpu_grpc.pb.go (1)
  • GpuService_WatchGpusClient (100-100)
api/device/v1alpha1/gpu_conversion.go (1)
  • FromProto (25-32)
client-go/client/versioned/scheme/register.go (2)
api/device/v1alpha1/register.go (2)
  • SchemeBuilder (31-31)
  • AddToScheme (34-34)
client-go/client/versioned/fake/register.go (1)
  • AddToScheme (49-49)
client-go/nvgrpc/config.go (1)
client-go/version/version.go (1)
  • UserAgent (28-35)
client-go/client/versioned/typed/device/v1alpha1/device_client.go (3)
client-go/client/versioned/clientset.go (4)
  • NewForConfig (48-60)
  • NewForConfigAndClient (64-81)
  • NewForConfigOrDie (85-92)
  • New (95-99)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/nvgrpc/client_conn.go (1)
  • ClientConnFor (26-72)
client-go/examples/fake-server/main.go (5)
commons/pkg/server/server.go (1)
  • NewServer (375-396)
api/gen/go/device/v1alpha1/gpu_grpc.pb.go (1)
  • RegisterGpuServiceServer (143-152)
api/device/v1alpha1/gpu_types.go (3)
  • GPU (55-61)
  • GPUSpec (24-30)
  • GPUStatus (35-45)
api/gen/go/device/v1alpha1/gpu.pb.go (9)
  • ObjectMeta (40-53)
  • ObjectMeta (66-66)
  • ObjectMeta (81-83)
  • Condition (380-398)
  • Condition (411-411)
  • Condition (426-428)
  • Gpu (159-169)
  • Gpu (182-182)
  • Gpu (197-199)
api/device/v1alpha1/gpu_conversion.go (1)
  • ToProto (35-40)
client-go/examples/controller-shim/main.go (7)
client-go/client/versioned/clientset.go (1)
  • New (95-99)
client-go/client/versioned/typed/device/v1alpha1/device_client.go (1)
  • New (74-79)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/informers/externalversions/factory.go (1)
  • NewSharedInformerFactory (91-93)
client-go/client/versioned/scheme/register.go (1)
  • Scheme (28-28)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
api/device/v1alpha1/gpu_types.go (1)
  • GPU (55-61)
client-go/listers/device/v1alpha1/gpu.go (3)
api/device/v1alpha1/gpu_types.go (1)
  • GPU (55-61)
client-go/listers/device/v1alpha1/expansion_generated.go (1)
  • GPUListerExpansion (21-21)
api/device/v1alpha1/register.go (1)
  • Resource (25-27)
api/device/v1alpha1/gpu_types.go (1)
api/gen/go/device/v1alpha1/gpu.pb.go (9)
  • Condition (380-398)
  • Condition (411-411)
  • Condition (426-428)
  • ObjectMeta (40-53)
  • ObjectMeta (66-66)
  • ObjectMeta (81-83)
  • ListMeta (100-112)
  • ListMeta (125-125)
  • ListMeta (140-142)
🪛 checkmake (0.2.2)
client-go/Makefile

[warning] 187-187: Target "tools" should be declared PHONY.

(phonydeclared)

🪛 LanguageTool
client-go/DEVELOPMENT.md

[style] ~77-~77: This phrase is redundant. Consider using “inside”.
Context: ... informers/) The directory structure inside of hack/overlays/ *must exactly mirror...

(OUTSIDE_OF)

🪛 markdownlint-cli2 (0.18.1)
client-go/DEVELOPMENT.md

10-10: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


11-11: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)

🔇 Additional comments (57)
client-go/hack/boilerplate.go.txt (1)

1-13: License header is complete and compliant.

The Apache 2.0 license header is properly formatted with the copyright notice, license URL, and all required disclaimers. This boilerplate template will be used by code generation tools to prepend headers to generated files.

client-go/hack/boilerplate_overlay.go.txt (1)

1-15: License header and generated code notice are properly formatted.

The Apache 2.0 license header matches the standard boilerplate, and the "Code generated by client-gen and gRPC overlay. DO NOT EDIT." notice (line 15) appropriately warns against manual edits of overlay-applied files. This template will be used by the overlay application workflow to mark generated files as auto-generated.

client-go/examples/README.md (1)

1-38: Documentation is clear and well-organized.

The README effectively communicates the purpose of each example, provides straightforward prerequisites and setup instructions, and accurately describes the directory structure. The table links (lines 9–11) now use correct relative paths (./basic-client, ./streaming-daemon, ./controller-shim) that will resolve properly from the examples/ directory context—this incorporates the feedback from the previous review comment successfully.

The instruction on line 30 appropriately assumes execution from the repository root, which is a common pattern and poses no confusion when combined with the relative table links that serve browser/editor navigation.

client-go/client/versioned/typed/device/v1alpha1/fake/doc.go (1)

1-18: Generated fake client looks correct; prefer envtest for controller tests.

The generated doc.go file follows standard client-go patterns with proper license header, generation notice, and package documentation. However, when writing actual test code for Kubernetes controllers, prefer envtest over fake clients for more realistic integration testing.

Based on learnings, envtest provides better coverage by running against a real API server rather than in-memory fakes.

client-go/version/version_test.go (2)

10-11: Good cleanup pattern.

The defer ensures GitVersion is restored even if the test fails or panics.


9-19: The test correctly saves and restores the package-level GitVersion variable using defer. Since tests within a package run sequentially by default and this test does not call t.Parallel(), there is no risk of concurrent access or race conditions.

Likely an incorrect or invalid review comment.

client-go/client/versioned/typed/device/v1alpha1/doc.go (1)

1-18: LGTM: Generated code follows standard conventions.

The file correctly includes the Apache 2.0 license header, generation notice, and package-level documentation as required by coding guidelines.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1)

17-24: LGTM: ClientConn implementation is appropriate for fake client.

The method correctly returns a nil *grpc.ClientConn cast to the interface, which is appropriate for a fake implementation that uses an in-memory ObjectTracker instead of actual gRPC connections. The documentation clearly explains this behavior.

api/go.mod (3)

3-3: Go toolchain update looks good.

The update from go 1.25.0 to go 1.25.5 is a patch-level toolchain update that should include bug fixes and improvements.


6-6: Dependency version is current.

The addition of github.com/google/go-cmp v0.7.0 is appropriate. This is the latest stable version and suitable for testing and comparison utilities in the codebase.


16-34: k8s.io/apimachinery v0.34.1 is stable and compatible.

No known vulnerabilities exist for this version. It is current (published August 2025), part of the active Kubernetes 1.34 support window, and the related ecosystem dependencies are properly aligned. The version safely integrates with client-go SDK as intended.

client-go/DEVELOPMENT.md (1)

1-105: LGTM: Comprehensive development documentation.

The DEVELOPMENT.md provides clear, well-structured guidance covering prerequisites, workflow, code generation pipeline, overlay patterns, directory structure, and housekeeping. The content accurately reflects the PR's multi-stage code generation approach.

client-go/listers/device/v1alpha1/gpu.go (1)

1-46: LGTM: Generated lister follows Kubernetes conventions.

The GPULister implementation correctly follows client-go patterns with a typed interface, read-only semantics clearly documented, and proper initialization using the ResourceIndexer pattern. The code generation marker and license header are present.

client-go/listers/device/v1alpha1/expansion_generated.go (1)

1-21: LGTM: Standard expansion interface pattern.

The empty GPUListerExpansion interface follows the standard Kubernetes pattern for allowing custom methods to be added to generated listers without modifying generated code. The file is properly marked as generated with appropriate license headers.

client-go/nvgrpc/options.go (1)

38-50: LGTM: Interceptor options follow functional pattern.

The WithUnaryInterceptor and WithStreamInterceptor functions correctly append interceptors to their respective chains, allowing multiple interceptors to be composed together. The implementation properly follows the functional options pattern.

api/device/v1alpha1/gpu_types.go (4)

21-30: LGTM: GPUSpec is well-documented.

The GPUSpec type clearly documents the UUID field with its expected format and example. The deepcopy generation annotation is correctly placed.


32-45: LGTM: GPUStatus follows Kubernetes conventions.

The GPUStatus correctly uses metav1.Condition for the Conditions field, following standard Kubernetes API patterns. The RecommendedAction field is well-documented with appropriate optional markers.


47-61: LGTM: GPU resource annotations are appropriate.

The genclient annotations correctly specify this as a non-namespaced, read-only resource (get/list/watch only) with no status subresource. The struct composition with TypeMeta and ObjectMeta follows standard Kubernetes resource patterns.


63-71: LGTM: GPUList follows standard list patterns.

The GPUList type correctly includes TypeMeta, ListMeta, and an Items slice, following the standard Kubernetes list resource pattern. The deepcopy and runtime.Object annotations are properly configured.

api/proto/device/v1alpha1/gpu.proto (4)

53-70: LGTM! Gpu message follows Kubernetes resource model.

The refactoring to use ObjectMeta and the addition of GpuStatus correctly implements the Kubernetes Spec/Status pattern. The comments provide clear guidance on resource naming conventions.


72-78: GpuList structure updated consistently.

The addition of ListMeta and repositioning of items field aligns with the ObjectMeta/ListMeta pattern. Note that changing field positions is a protobuf breaking change, which is acknowledged in the PR objectives.


80-117: Status types are well-structured and documented.

GpuSpec, GpuStatus, and Condition messages follow Kubernetes API conventions with comprehensive field documentation. The Condition type correctly implements the standard Kubernetes condition pattern.

Based on learnings, comprehensive comments for all fields are present as required.


119-185: Service definition and request/response messages are complete.

The GpuService RPCs (Get, List, Watch) provide appropriate operations for GPU resource management. The addition of resource_version fields to ListGpusRequest and WatchGpusRequest enables versioned operations and watch semantics as intended. Event types in WatchGpusResponse are clearly documented.

client-go/client/versioned/typed/device/v1alpha1/gpu.go (4)

31-49: Interface design follows client-go conventions.

The GPUsGetter and GPUInterface definitions correctly follow Kubernetes client-go patterns. The GPUExpansion interface allows for future extensibility without breaking changes.

As per coding guidelines, using client-go patterns for Kubernetes API interactions is the recommended approach.


51-57: Constructor correctly initializes the GPU client.

The newGPUs constructor properly wires the gRPC client and scopes the logger with WithName("gpus"), which aids in debugging and observability.


59-87: Get and List methods are correctly implemented.

Both methods properly handle gRPC calls, perform protobuf-to-internal conversions, and log operations at appropriate verbosity levels. Errors are returned directly without wrapping, which is correct for gRPC calls to preserve status codes.


89-103: Watch method correctly manages streaming and context lifecycle.

The Watch implementation properly creates a cancellable context, handles error cleanup by calling cancel before returning, and passes the cancel function to nvgrpc.NewWatcher for proper stream closure. This prevents resource leaks.

As per coding guidelines, this implements proper shutdown handling with context cancellation.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (5)

9-22: Client interface and struct follow client-go patterns.

The DeviceV1alpha1Interface correctly embeds GPUsGetter and exposes ClientConn for transport access. The GPUs() method properly delegates to the newGPUs constructor for resource client instantiation.


24-35: NewForConfig correctly handles connection setup.

The shallow copy of the config prevents mutation, and error handling for connection establishment is appropriate. The delegation to NewForConfigAndClient avoids code duplication.


37-44: NewForConfigAndClient properly initializes the client with provided connection.

The method correctly prioritizes the provided connection over config transport values and scopes the logger appropriately. The error return enables consistent API patterns across constructors.


46-63: OrDie and minimal constructors follow client-go conventions.

NewForConfigOrDie correctly panics on error (expected for "OrDie" pattern), and New provides a minimal constructor with a discarded logger for simple use cases. Both patterns align with Kubernetes client-go practices.


65-73: ClientConn accessor includes appropriate nil safety.

The nil check on the receiver prevents potential panics and follows defensive programming practices.

api/device/v1alpha1/zz_generated.conversion.go (6)

11-22: FromProtobuf method implements proper nil safety.

The conversion from protobuf Gpu to internal GPU type correctly checks for nil source and delegates to field-specific converters. The structure follows generated code best practices.


23-33: Condition conversion correctly maps all fields.

The FromProtobufCondition method properly converts all condition fields including the Status cast to v1.ConditionStatus and uses the FromProtobufTimestamp helper for timestamp conversion.


34-49: List conversion handles nil safety and slice allocation correctly.

The FromProtobufList method properly checks for nil source and Items, allocates the slice with the correct length, and converts each element. The pattern is appropriate for generated conversion code.


50-64: Metadata converters implement required subset of k8s metadata.

FromProtobufListMeta and FromProtobufObjectMeta correctly map the essential fields (Name, ResourceVersion) with appropriate nil checks. This aligns with the proto definition of ObjectMeta and ListMeta as subsets of Kubernetes metadata types.


65-84: Spec and Status converters handle field mappings correctly.

FromProtobufSpec correctly maps the UUID field with appropriate case conversion (Uuid -> UUID). FromProtobufStatus handles the Conditions slice with proper nil checking and element-by-element conversion.


85-142: ToProtobuf methods correctly reverse the conversion direction.

All ToProtobuf methods properly convert from internal types to protobuf types with appropriate nil safety where needed. The conversions mirror the FromProtobuf logic correctly, including the Status to string cast and slice handling.

client-go/examples/fake-server/README.md (1)

1-18: README provides clear documentation for the fake server.

The README effectively documents the fake server's purpose, usage, and behavior. The instructions are concise and the simulation behavior (8 GPUs with 2-second status toggling) is well-explained for testing Watch streams and controllers.

client-go/client/versioned/scheme/doc.go (1)

1-18: Package documentation follows Go conventions.

The doc.go file correctly provides package-level documentation as required by coding guidelines. The license header and generated code notice are appropriate.

As per coding guidelines, package-level godoc is required for all Go packages.

client-go/nvgrpc/config_test.go (3)

20-59: Target precedence test correctly validates configuration defaults.

The table-driven test structure follows Go testing best practices and comprehensively covers the precedence order (explicit > env var > default). The use of t.Setenv ensures proper cleanup between subtests.

As per coding guidelines, this test uses the table-driven format when testing multiple scenarios.


61-80: UserAgent default test validates expected behavior.

The test correctly verifies that Default() populates an empty UserAgent and preserves custom values. The subtest structure improves clarity and isolation.


82-120: Validation test comprehensively covers required field checks.

The table-driven test correctly validates that Config.Validate() enforces required fields (Target, UserAgent) and allows valid configurations. The error checking pattern is idiomatic.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (2)

9-23: Next method correctly handles stream events and conversions.

The Next() method properly receives stream events, handles errors immediately, and converts protobuf objects to runtime.Object using FromProto. The use of GetType() and GetObject() accessor methods is safe.


25-27: Close method correctly closes the gRPC stream.

The Close() method properly calls CloseSend() on the underlying stream and propagates any errors, ensuring proper resource cleanup.

client-go/nvgrpc/watcher.go (1)

38-76: LGTM: Stop() is now properly idempotent.

The sync.Once field (line 44) and its usage in Stop() (line 68-75) correctly ensures that shutdown happens exactly once, addressing the previous race condition concern. This makes Stop() safe for concurrent calls, including the defer w.Stop() in receive().

client-go/client/versioned/typed/device/v1alpha1/device_client.go (5)

25-28: LGTM!

The interface design is clean and follows good Go practices by exposing the underlying connection via ClientConn() and embedding resource-specific getters.


30-34: LGTM!

The struct design appropriately encapsulates the gRPC connection and logger, following structured logging practices as specified in the coding guidelines.


36-38: LGTM!

The method correctly delegates to newGPUs(), which is implemented via the overlay pattern mentioned in the PR objectives.


62-79: LGTM!

Both constructors follow standard Kubernetes client-go patterns: NewForConfigOrDie for CLI tools that should fail fast, and New with a discard logger for cases where configuration is unavailable.


81-89: LGTM!

The ClientConn() method includes appropriate nil-safety checks and provides access to the underlying gRPC connection when needed.

client-go/Makefile (6)

19-83: LGTM!

The configuration section is well-structured with clear variable naming, appropriate fallbacks (e.g., GO_VERSION detection), and helpful error messaging for missing prerequisites (yq). The use of a centralized .versions.yaml file for tool versioning is a good practice for maintainability.


89-96: LGTM!

The all target follows a logical order (code-gen → test → build), and the help formatter uses the standard awk pattern for extracting target documentation.


100-103: LGTM!

The target dependencies are correctly ordered: generating the client, applying overlays, then generating listers/informers that depend on the overlaid client code. The final go mod tidy ensures module consistency.


115-144: LGTM!

The code generator targets are correctly configured with appropriate flags, dependencies on their respective tools, and clean targets to remove stale generated code. The flags follow standard Kubernetes code-generator conventions.


146-176: LGTM!

The overlay and cleanup targets provide appropriate granularity for managing generated code and tools. The hierarchical clean targets (clean, purge, clean-*) offer good flexibility for different cleanup scenarios.


198-213: LGTM!

The go-install-tool macro is well-designed: it avoids reinstalling identical versions via version suffixes, uses symlinks for convenient access, and correctly sets GOTOOLCHAIN to ensure the right Go version is used for tool compilation.

Copy link
Contributor

@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

♻️ Duplicate comments (6)
.versions.yaml (1)

49-50: Update goverter version - v1.9.2 does not exist.

The goverter version v1.9.2 specified does not exist. The latest released version is v1.8.2. Update to use an actual released version.

Run the following script to verify the latest goverter release:

#!/bin/bash
# Check the latest release of goverter
gh api repos/jmattheis/goverter/releases/latest --jq '.tag_name'
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (2)

1-1: Add package-level godoc comment.

The package lacks documentation. As per coding guidelines, package-level godoc is required for all Go packages.

As per coding guidelines.


13-15: Add function comment for exported method.

The GPUs() method is missing documentation. As per coding guidelines, function comments are required for all exported Go functions.

As per coding guidelines.

client-go/hack/overlays/client/versioned/integration_test.go (1)

210-214: Avoid calling t.Errorf from a goroutine.

Calling t.Errorf from a goroutine is unsafe and can cause race conditions. The cache's Start method runs until context cancellation, so errors should be captured via a channel.

api/proto/device/v1alpha1/gpu.proto (1)

35-37: Fix inconsistent indentation in comment blocks.

Some comment lines use tabs while surrounding lines use spaces, creating inconsistent formatting.

Also applies to: 47-48

client-go/Makefile (1)

187-187: Declare the tools target as PHONY.

The tools target should be declared .PHONY since it doesn't produce a file output and serves as a convenience alias for tool binaries.

🔎 Proposed fix
+.PHONY: tools
 tools: $(CLIENT_GEN) $(LISTER_GEN) $(INFORMER_GEN)
🧹 Nitpick comments (9)
client-go/version/version_test.go (3)

9-9: Refactor test name to follow the coding guideline convention.

The test name should follow the format TestFunctionName_Scenario_ExpectedBehavior. Consider renaming to something like TestUserAgent_WithCustomVersion_ReturnsFormattedString.

As per coding guidelines for **/*_test.go: "Name Go tests descriptively using format: TestFunctionName_Scenario_ExpectedBehavior"


16-18: Use testify for assertions per coding guidelines.

The test uses plain t.Errorf for assertions, but the coding guidelines specify using testify/assert or testify/require.

🔎 Proposed refactor using testify/assert
 import (
-	"fmt"
 	"runtime"
 	"testing"
+
+	"github.com/stretchr/testify/assert"
 )

 func TestUserAgent(t *testing.T) {
 	originalVersion := GitVersion
 	defer func() { GitVersion = originalVersion }()

 	GitVersion = "v1.2.3-test"

-	expected := fmt.Sprintf("nvidia-device-api-client/v1.2.3-test (%s/%s)", runtime.GOOS, runtime.GOARCH)
-	if got := UserAgent(); got != expected {
-		t.Errorf("UserAgent() = %q, want %q", got, expected)
-	}
+	expected := "nvidia-device-api-client/v1.2.3-test (" + runtime.GOOS + "/" + runtime.GOARCH + ")"
+	assert.Equal(t, expected, UserAgent())
 }

As per coding guidelines for **/*_test.go: "Use testify/assert and testify/require for assertions in Go tests"


9-19: Consider table-driven tests for multiple scenarios.

While the current test correctly verifies the UserAgent function, consider using a table-driven approach to test multiple scenarios (e.g., default "devel" version, various version formats, edge cases).

🔎 Example table-driven refactor
 func TestUserAgent(t *testing.T) {
+	tests := []struct {
+		name       string
+		gitVersion string
+	}{
+		{"custom version", "v1.2.3-test"},
+		{"devel version", "devel"},
+		{"empty version", ""},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			originalVersion := GitVersion
+			defer func() { GitVersion = originalVersion }()
+
+			GitVersion = tt.gitVersion
+
+			expected := "nvidia-device-api-client/" + tt.gitVersion + " (" + runtime.GOOS + "/" + runtime.GOARCH + ")"
+			assert.Equal(t, expected, UserAgent())
+		})
+	}
-	originalVersion := GitVersion
-	defer func() { GitVersion = originalVersion }()
-
-	GitVersion = "v1.2.3-test"
-
-	expected := fmt.Sprintf("nvidia-device-api-client/v1.2.3-test (%s/%s)", runtime.GOOS, runtime.GOARCH)
-	if got := UserAgent(); got != expected {
-		t.Errorf("UserAgent() = %q, want %q", got, expected)
-	}
 }

As per coding guidelines for **/*_test.go: "Write table-driven tests when testing multiple scenarios in Go"

Note: The core test logic (state save/restore, version override, format verification) is correct and properly implemented.

client-go/DEVELOPMENT.md (2)

10-11: Optional: Fix markdown list indentation.

The nested list items use 4 spaces instead of the standard 2 spaces for indentation, which markdownlint flags.

🔎 Suggested fix
 * **yq**: Required to parse version configuration.
-    * *macOS*: `brew install yq`
-    * *Linux*: See [yq installation](https://github.com/mikefarah/yq)
+  * *macOS*: `brew install yq`
+  * *Linux*: See [yq installation](https://github.com/mikefarah/yq)

77-77: Optional: Simplify phrasing.

"inside of" can be simplified to "inside" for more concise documentation.

🔎 Suggested fix
-The directory structure inside of `hack/overlays/` **must exactly mirror** the structure of the generated code.
+The directory structure inside `hack/overlays/` **must exactly mirror** the structure of the generated code.
client-go/nvgrpc/config.go (1)

40-49: Add a public method to configure the logger.

The logger field is unexported and there's no public setter method, which prevents users from configuring custom logging. Users must rely on Default() setting a discard logger, limiting observability.

🔎 Proposed addition of WithLogger method

Add a method to allow users to configure a logger:

+// WithLogger sets the logger for the Config.
+func (c *Config) WithLogger(logger logr.Logger) *Config {
+	c.logger = logger
+	return c
+}

This enables fluent configuration like:

config := &nvgrpc.Config{Target: "unix://..."}
config.WithLogger(myLogger).Default()
client-go/nvgrpc/watcher_test.go (1)

31-58: Consider using testify for more expressive assertions.

The tests use basic Go assertions (t.Fatalf, t.Errorf), which work but are less expressive than testify assertions. The coding guidelines recommend using testify/assert and testify/require for clearer test failures.

As per coding guidelines for **/*_test.go: "Use testify/assert and testify/require for assertions in Go tests"

Example refactor using testify
+import (
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)

 func TestWatcher_NormalEvents(t *testing.T) {
 	// ... setup ...
 	
 	wantTypes := []watch.EventType{watch.Added, watch.Modified, watch.Deleted}
-	if len(got) != len(wantTypes) {
-		t.Fatalf("got %d events, want %d", len(got), len(wantTypes))
-	}
+	require.Len(t, got, len(wantTypes), "unexpected number of events")
+	
 	for i, ev := range got {
-		if ev.Type != wantTypes[i] {
-			t.Errorf("event %d: got type %v, want %v", i, ev.Type, wantTypes[i])
-		}
+		assert.Equal(t, wantTypes[i], ev.Type, "event %d type mismatch", i)
 	}
 }

Also applies to: 60-83, 85-118, 120-152, 154-177

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1)

57-63: Consider accepting an optional logger parameter in New().

The New() constructor always uses a discard logger with no way to configure logging afterwards. For production observability, consider adding a variadic options parameter or a separate NewWithLogger() constructor.

🔎 Proposed enhancement using functional options
+type ClientOption func(*DeviceV1alpha1Client)
+
+func WithLogger(logger logr.Logger) ClientOption {
+	return func(c *DeviceV1alpha1Client) {
+		c.logger = logger
+	}
+}
+
 // New creates a new DeviceV1alpha1Client for the given gRPC client connection.
-func New(c grpc.ClientConnInterface) *DeviceV1alpha1Client {
-	return &DeviceV1alpha1Client{
+func New(c grpc.ClientConnInterface, opts ...ClientOption) *DeviceV1alpha1Client {
+	client := &DeviceV1alpha1Client{
 		conn:   c,
 		logger: logr.Discard(),
 	}
+	for _, opt := range opts {
+		opt(client)
+	}
+	return client
 }
client-go/Makefile (1)

198-213: Simplify redundant error suppression in go-install-tool.

Line 208 uses rm -f $(1) || true, but the -f flag already suppresses errors, making || true redundant.

🔎 Proposed simplification
 echo "Downloading $${package}" ;\
-rm -f $(1) || true ;\
+rm -f $(1) ;\
 GOBIN=$(LOCALBIN) GOTOOLCHAIN=$(GO_VERSION) go install $${package} ;\
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1776d86 and 1072d57.

⛔ Files ignored due to path filters (28)
  • api/device/v1alpha1/zz_generated.conversion.go is excluded by !api/**/zz_generated.*
  • api/device/v1alpha1/zz_generated.deepcopy.go is excluded by !api/**/zz_generated.*
  • api/gen/go/device/v1alpha1/gpu.pb.go is excluded by !**/*.pb.go, !**/gen/**, !api/gen/**
  • api/go.sum is excluded by !**/*.sum
  • client-go/client/versioned/clientset.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/clientset_generated.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/register.go is excluded by !client-go/client/**
  • client-go/client/versioned/integration_test.go is excluded by !client-go/client/**
  • client-go/client/versioned/scheme/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/scheme/register.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/device_client.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_gpu.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/generated_expansion.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/gpu.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go is excluded by !client-go/client/**
  • client-go/go.sum is excluded by !**/*.sum
  • client-go/informers/externalversions/device/interface.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/device/v1alpha1/gpu.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/device/v1alpha1/interface.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/factory.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/generic.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go is excluded by !client-go/informers/**
  • client-go/listers/device/v1alpha1/expansion_generated.go is excluded by !client-go/listers/**
  • client-go/listers/device/v1alpha1/gpu.go is excluded by !client-go/listers/**
📒 Files selected for processing (47)
  • .coderabbit.yaml (1 hunks)
  • .gitignore (1 hunks)
  • .versions.yaml (1 hunks)
  • api/Makefile (5 hunks)
  • api/device/v1alpha1/converter.go (1 hunks)
  • api/device/v1alpha1/doc.go (1 hunks)
  • api/device/v1alpha1/gpu_conversion.go (1 hunks)
  • api/device/v1alpha1/gpu_conversion_test.go (1 hunks)
  • api/device/v1alpha1/gpu_types.go (1 hunks)
  • api/device/v1alpha1/register.go (1 hunks)
  • api/go.mod (2 hunks)
  • api/hack/boilerplate.go.txt (1 hunks)
  • api/proto/device/v1alpha1/gpu.proto (4 hunks)
  • client-go/DEVELOPMENT.md (1 hunks)
  • client-go/Makefile (1 hunks)
  • client-go/README.md (1 hunks)
  • client-go/examples/README.md (1 hunks)
  • client-go/examples/basic-client/README.md (1 hunks)
  • client-go/examples/basic-client/main.go (1 hunks)
  • client-go/examples/controller-shim/README.md (1 hunks)
  • client-go/examples/controller-shim/main.go (1 hunks)
  • client-go/examples/fake-server/README.md (1 hunks)
  • client-go/examples/fake-server/main.go (1 hunks)
  • client-go/examples/streaming-daemon/README.md (1 hunks)
  • client-go/examples/streaming-daemon/main.go (1 hunks)
  • client-go/go.mod (1 hunks)
  • client-go/hack/apply-overlays.sh (1 hunks)
  • client-go/hack/boilerplate.go.txt (1 hunks)
  • client-go/hack/boilerplate_overlay.go.txt (1 hunks)
  • client-go/hack/overlays/client/versioned/clientset.go (1 hunks)
  • client-go/hack/overlays/client/versioned/integration_test.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1 hunks)
  • client-go/nvgrpc/client_conn.go (1 hunks)
  • client-go/nvgrpc/client_conn_test.go (1 hunks)
  • client-go/nvgrpc/config.go (1 hunks)
  • client-go/nvgrpc/config_test.go (1 hunks)
  • client-go/nvgrpc/interceptors.go (1 hunks)
  • client-go/nvgrpc/interceptors_test.go (1 hunks)
  • client-go/nvgrpc/options.go (1 hunks)
  • client-go/nvgrpc/options_test.go (1 hunks)
  • client-go/nvgrpc/watcher.go (1 hunks)
  • client-go/nvgrpc/watcher_test.go (1 hunks)
  • client-go/version/version.go (1 hunks)
  • client-go/version/version_test.go (1 hunks)
✅ Files skipped from review due to trivial changes (5)
  • client-go/hack/boilerplate_overlay.go.txt
  • client-go/README.md
  • client-go/nvgrpc/config_test.go
  • client-go/examples/streaming-daemon/README.md
  • client-go/hack/boilerplate.go.txt
🚧 Files skipped from review as they are similar to previous changes (20)
  • api/device/v1alpha1/gpu_conversion_test.go
  • client-go/examples/README.md
  • client-go/version/version.go
  • client-go/nvgrpc/client_conn.go
  • client-go/nvgrpc/client_conn_test.go
  • client-go/examples/controller-shim/README.md
  • client-go/go.mod
  • client-go/examples/basic-client/main.go
  • client-go/nvgrpc/options.go
  • client-go/examples/fake-server/README.md
  • api/device/v1alpha1/register.go
  • client-go/examples/fake-server/main.go
  • client-go/nvgrpc/interceptors_test.go
  • client-go/nvgrpc/options_test.go
  • client-go/examples/controller-shim/main.go
  • .gitignore
  • api/hack/boilerplate.go.txt
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go
  • api/device/v1alpha1/converter.go
  • client-go/examples/basic-client/README.md
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.go: Follow standard Go conventions with gofmt and golint
Use structured logging via log/slog in Go code
Wrap errors with context using fmt.Errorf("context: %w", err) in Go code
Within retry.RetryOnConflict blocks, return errors without wrapping to preserve retry behavior
Use meaningful variable names such as synced over ok for cache sync checks
Use client-go for Kubernetes API interactions in Go code
Prefer informers over direct API calls for watching Kubernetes resources
Implement proper shutdown handling with context cancellation in Go code
Package-level godoc required for all Go packages
Function comments required for all exported Go functions
Use inline comments for complex logic only in Go code
TODO comments should reference issues in Go code
Extract informer event handler setup into helper methods
Use separate informers for different Kubernetes resource types

Files:

  • client-go/nvgrpc/interceptors.go
  • api/device/v1alpha1/gpu_types.go
  • client-go/nvgrpc/config.go
  • client-go/version/version_test.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • api/device/v1alpha1/doc.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/nvgrpc/watcher.go
  • client-go/nvgrpc/watcher_test.go
  • api/device/v1alpha1/gpu_conversion.go
  • client-go/examples/streaming-daemon/main.go
  • client-go/hack/overlays/client/versioned/clientset.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go
**/go.mod

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use go.mod for each service as a separate Go module with semantic import versioning

Files:

  • api/go.mod
**/*_test.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*_test.go: Use envtest for testing Kubernetes controllers instead of fake clients
Use testify/assert and testify/require for assertions in Go tests
Write table-driven tests when testing multiple scenarios in Go
Name Go tests descriptively using format: TestFunctionName_Scenario_ExpectedBehavior

Files:

  • client-go/version/version_test.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/nvgrpc/watcher_test.go
🧠 Learnings (16)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Keep Go dependencies minimal and up-to-date

Applied to files:

  • .versions.yaml
  • api/go.mod
  • api/Makefile
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code

Applied to files:

  • .versions.yaml
  • client-go/hack/apply-overlays.sh
  • api/go.mod
  • client-go/nvgrpc/config.go
  • client-go/DEVELOPMENT.md
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/Makefile
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Use `envtest` for testing Kubernetes controllers instead of fake clients

Applied to files:

  • .versions.yaml
  • client-go/version/version_test.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/hack/overlays/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Follow standard Go conventions with gofmt and golint

Applied to files:

  • .versions.yaml
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/go.mod : Use `go.mod` for each service as a separate Go module with semantic import versioning

Applied to files:

  • api/go.mod
📚 Learning: 2025-12-01T17:53:20.067Z
Learnt from: jtschelling
Repo: NVIDIA/NVSentinel PR: 455
File: docs/designs/013-remediation-plugins.md:162-204
Timestamp: 2025-12-01T17:53:20.067Z
Learning: Code examples in design documents (docs/designs/) in the NVSentinel repository are illustrative stubs meant to show intent and architectural concepts, and do not need to be 100% correct or complete implementations (e.g., undefined variables, missing error handling, incomplete struct initialization are acceptable).

Applied to files:

  • api/go.mod
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Prefer informers over direct API calls for watching Kubernetes resources

Applied to files:

  • api/go.mod
  • client-go/nvgrpc/watcher.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Name Go tests descriptively using format: `TestFunctionName_Scenario_ExpectedBehavior`

Applied to files:

  • client-go/version/version_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Function comments required for all exported Go functions

Applied to files:

  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Package-level godoc required for all Go packages

Applied to files:

  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : TODO comments should reference issues in Go code

Applied to files:

  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use meaningful variable names such as `synced` over `ok` for cache sync checks

Applied to files:

  • client-go/hack/overlays/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Implement proper shutdown handling with context cancellation in Go code

Applied to files:

  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/nvgrpc/watcher.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to data-models/protobufs/**/*.proto : Include comprehensive comments for all fields in Protocol Buffer messages

Applied to files:

  • api/proto/device/v1alpha1/gpu.proto
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to data-models/protobufs/**/*.proto : Use semantic versioning for breaking changes in Protocol Buffer messages

Applied to files:

  • api/proto/device/v1alpha1/gpu.proto
🧬 Code graph analysis (9)
client-go/nvgrpc/config.go (1)
client-go/version/version.go (1)
  • UserAgent (28-35)
client-go/version/version_test.go (1)
client-go/version/version.go (2)
  • GitVersion (25-25)
  • UserAgent (28-35)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (1)
  • GPUInterface (22-27)
client-go/hack/overlays/client/versioned/integration_test.go (5)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/hack/overlays/client/versioned/clientset.go (2)
  • NewForConfigAndClient (48-65)
  • New (79-83)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (2)
  • NewForConfigAndClient (39-44)
  • New (58-63)
api/device/v1alpha1/gpu_types.go (1)
  • GPU (55-61)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
client-go/nvgrpc/watcher_test.go (1)
client-go/nvgrpc/watcher.go (1)
  • NewWatcher (49-64)
api/device/v1alpha1/gpu_conversion.go (2)
api/device/v1alpha1/converter.go (1)
  • Converter (30-104)
api/device/v1alpha1/gpu_types.go (2)
  • GPU (55-61)
  • GPUList (67-71)
client-go/examples/streaming-daemon/main.go (5)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (2)
  • New (58-63)
  • NewForConfigAndClient (39-44)
client-go/nvgrpc/options.go (4)
  • DialOption (23-23)
  • WithLogger (32-36)
  • WithUnaryInterceptor (39-43)
  • WithStreamInterceptor (46-50)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/nvgrpc/client_conn.go (1)
  • ClientConnFor (26-72)
api/device/v1alpha1/gpu_types.go (1)
  • GPU (55-61)
client-go/hack/overlays/client/versioned/clientset.go (3)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (6)
  • DeviceV1alpha1Interface (9-12)
  • DeviceV1alpha1Client (15-18)
  • NewForConfig (27-35)
  • NewForConfigAndClient (39-44)
  • NewForConfigOrDie (48-55)
  • New (58-63)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/nvgrpc/client_conn.go (1)
  • ClientConnFor (26-72)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1)
api/device/v1alpha1/gpu_conversion.go (1)
  • FromProto (25-32)
🪛 checkmake (0.2.2)
client-go/Makefile

[warning] 187-187: Target "tools" should be declared PHONY.

(phonydeclared)

🪛 LanguageTool
client-go/DEVELOPMENT.md

[style] ~77-~77: This phrase is redundant. Consider using “inside”.
Context: ... informers/) The directory structure inside of hack/overlays/ *must exactly mirror...

(OUTSIDE_OF)

🪛 markdownlint-cli2 (0.18.1)
client-go/DEVELOPMENT.md

10-10: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


11-11: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)

🔇 Additional comments (40)
api/go.mod (2)

3-3: LGTM! Go toolchain update is appropriate.

The Go toolchain update from 1.25.0 to 1.25.5 is a patch-level update that's appropriate for this PR.


6-6: LGTM! Dependencies align with client-go SDK objectives.

The new dependencies (go-cmp, k8s.io/apimachinery, and related transitive dependencies) are appropriate for the Kubernetes client-go SDK integration and API generation work described in the PR objectives.

Also applies to: 16-33

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (3)

10-12: LGTM! Clean adapter abstraction.

The gpuStreamAdapter provides a clean abstraction over the gRPC stream, wrapping it to provide Kubernetes-compatible event semantics.


14-23: LGTM! Proper error handling and conversion logic.

The Next() method correctly:

  • Handles gRPC Recv() errors with early return
  • Converts protobuf messages to runtime.Object via FromProto
  • Returns the event type and converted object

25-27: LGTM! Appropriate stream cleanup.

The Close() method correctly calls CloseSend() to properly close the client-side gRPC stream.

api/device/v1alpha1/gpu_conversion.go (3)

15-15: LGTM! Appropriate build tag.

The !goverter build tag correctly excludes this file when goverter generates conversion code, preventing conflicts.


21-32: LGTM! Clean singleton pattern with proper nil handling.

The converter singleton and FromProto helper correctly:

  • Initialize the singleton converter instance
  • Check for nil input and return nil
  • Delegate to the generated converter and handle pointer conversions properly

34-56: LGTM! Consistent conversion helpers.

All conversion helpers (ToProto, FromProtoList, ToProtoList) follow the same pattern with:

  • Proper nil checks
  • Correct pointer handling
  • Delegation to the converter implementation
api/Makefile (6)

19-37: LGTM! Well-structured version and package scaffolding.

The string manipulation helpers, API version variables, and package path helpers provide clean, maintainable support for per-version code generation workflows.


55-79: LGTM! Clean tool management and version centralization.

The GO_VERSION detection, tool binary definitions, and centralized version loading from .versions.yaml provide good maintainability and consistency across the build system.


86-99: LGTM! Comprehensive code generation workflow.

The updated all target and new code-gen target properly orchestrate the multi-stage generation pipeline (tools → protos → deepcopy → conversion → tidy), aligning with the PR's objectives for generated client-go SDK.


111-141: LGTM! Per-version generation targets are well-structured.

The proto, deepcopy, and conversion generation targets correctly:

  • Loop over API_VERSIONS for per-version processing
  • Use appropriate tool flags and options
  • Include clean targets for each generation type

143-167: LGTM! Comprehensive cleanup targets.

The clean, purge, and per-artifact clean targets provide thorough cleanup capabilities for all generated artifacts.


194-205: LGTM! Proper toolchain propagation.

The go-install-tool macro correctly propagates GOTOOLCHAIN=$(GO_VERSION) during tool installation, ensuring tools are built with the correct Go version.

api/device/v1alpha1/doc.go (1)

15-19: LGTM! Proper Kubernetes API group documentation.

The package documentation correctly includes:

  • Kubebuilder group marker (+groupName=device.nvidia.com)
  • Clear description of package contents (GPU resources, conversions)
  • Standard Go package doc format
.coderabbit.yaml (1)

19-24: LGTM! Appropriate exclusion of generated code.

The path_filters correctly exclude generated/boilerplate code paths (protobuf bindings, zz_generated.* files, generated clientset/listers/informers), which aligns with the PR's objective to add generated client-go SDK components.

client-go/hack/apply-overlays.sh (3)

5-5: LGTM! Strict error handling enabled.

The script correctly uses set -euo pipefail for strict error handling (exit on error, undefined variables, and pipeline failures).


7-20: LGTM! Proper validation checks.

The script includes appropriate validation:

  • Verifies boilerplate file exists
  • Ensures execution from repository root (checks go.mod)
  • Exits with clear error messages on validation failures

22-29: LGTM! Clean overlay application logic.

The find loop correctly:

  • Processes all .go files in the overlay directory
  • Strips the overlay prefix to compute destination paths
  • Creates destination directories as needed
  • Concatenates boilerplate with overlay source
  • Provides clear progress output
client-go/examples/streaming-daemon/main.go (3)

49-52: LGTM: Clean interceptor implementation.

The inline unary interceptor properly injects tracing metadata and delegates to the invoker. The implementation is straightforward and correct.


88-94: LGTM: Proper error handling for List operation.

The List operation correctly uses the timeout context and handles errors appropriately, logging the GPU count on success.


96-143: LGTM: Well-structured watch loop with proper cleanup.

The watch implementation demonstrates several best practices:

  • Deferred watcher cleanup with Stop()
  • Proper channel close detection
  • Watch error handling with status extraction
  • Type assertion safety check
  • Context cancellation handling

The event processing logic correctly extracts GPU readiness status from conditions.

client-go/nvgrpc/interceptors.go (2)

27-59: LGTM: Proper unary interceptor implementation.

The latency interceptor correctly:

  • Measures RPC duration without disrupting the call flow
  • Uses appropriate log levels for different scenarios (V(4) for context errors, Error() for failures, V(6) for success)
  • Preserves the original error for proper error propagation
  • Includes relevant metadata (method, duration, status code)

61-92: LGTM: Proper stream interceptor implementation.

The stream interceptor follows the same solid pattern as the unary interceptor. The success logging at V(4) (vs V(6) for unary) appears intentional, likely because stream establishment is more significant than individual unary calls.

client-go/hack/overlays/client/versioned/integration_test.go (4)

64-72: LGTM: Straightforward Get test.

The test properly validates the Get operation, checking both successful retrieval and the resource name.


88-129: LGTM: Comprehensive Watch flow test.

The test validates both the initial snapshot (ADDED events) and subsequent live updates (MODIFIED events), with proper timeout handling and type safety checks.


137-139: LGTM: Correct informer initialization order.

The code properly instantiates the informer before starting the factory, which is required to register it with the factory.


299-333: LGTM: Well-structured mock WatchGpus implementation.

The mock properly:

  • Sends initial snapshot under read lock
  • Handles context cancellation during snapshot
  • Streams live events from the watch channel
  • Returns on channel close or context cancellation
api/proto/device/v1alpha1/gpu.proto (2)

27-51: LGTM: Well-designed metadata messages.

The ObjectMeta and ListMeta messages properly mirror Kubernetes API conventions, enabling resource versioning, optimistic concurrency, and watch semantics. The comments appropriately reference the Kubernetes API conventions documentation.


152-167: LGTM: Resource version support for watch resumption.

Adding resource_version fields to ListGpusRequest and WatchGpusRequest enables clients to resume watches from a specific point and perform consistent list operations, aligning with Kubernetes watch semantics.

client-go/hack/overlays/client/versioned/clientset.go (3)

26-44: LGTM: Well-documented constructor with defensive copying.

The NewForConfig constructor properly validates input, creates the gRPC connection, and delegates to NewForConfigAndClient. The shallow copy at line 37 protects against config mutation. The documentation clearly explains when to use this vs. manually creating a connection.


46-65: LGTM: Robust validation and defensive copying.

The constructor properly validates both parameters and performs defensive copying before passing the config to the device client constructor. The nil checks provide clear error messages.


67-76: LGTM: Appropriate panic behavior for OrDie pattern.

The NewForConfigOrDie function follows the Kubernetes convention for "OrDie" constructors, panicking on configuration errors. This is appropriate for initialization code where recovery is not possible.

api/device/v1alpha1/gpu_types.go (4)

21-30: LGTM: Clean spec definition with clear documentation.

The GPUSpec properly defines the GPU identity with clear field documentation and format examples.


32-45: LGTM: Status definition follows Kubernetes conventions.

The GPUStatus correctly uses metav1.Condition for status conditions, aligning with Kubernetes best practices. Both fields are appropriately marked as optional.

As per coding guidelines.


47-61: LGTM: Appropriate genclient markers for read-only cluster resource.

The markers correctly configure this as:

  • A cluster-scoped resource (nonNamespaced)
  • Read-only verbs only (onlyVerbs=get,list,watch)
  • No separate status subresource (noStatus)

This configuration is appropriate for a hardware resource that's observed but not mutated through the API.


63-71: LGTM: Proper list type with required markers.

The GPUList includes the necessary deepcopy and runtime.Object markers, and properly embeds ListMeta for list pagination and versioning support.

client-go/nvgrpc/watcher.go (2)

48-63: LGTM! Well-structured watcher initialization.

The watcher is properly initialized with buffered channels, context cancellation support, and scoped logging. The race condition identified in previous reviews has been correctly addressed using sync.Once.


138-170: LGTM! Comprehensive error mapping for Informer integration.

The error translation logic correctly maps gRPC status codes to Kubernetes status reasons, with special handling for codes that should trigger Informer relist operations (410 Expired). The comment on line 148 clearly explains the critical behavior.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1)

65-73: LGTM! Defensive nil-check prevents panics.

The nil-check on the receiver (line 68) is good defensive programming that prevents potential nil pointer dereferences when accessing the connection.

@pteranodan
Copy link
Contributor Author

@coderabbitai full review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 20, 2025

✅ Actions performed

Full review triggered.

Copy link
Contributor

@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: 5

Caution

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

⚠️ Outside diff range comments (1)
api/go.mod (1)

1-34: Fix module version format to resolve pipeline failure.

The pipeline reports a critical error: gomod-lint expects local modules to use v0.0.0 (without timestamp), but the current version is v0.0.0-00010101000000-000000000000.

This is blocking the build pipeline. Ensure the replace directive or module version follows the expected format for local modules.

#!/bin/bash
# Verify the go.mod format and any replace directives
cat api/go.mod | grep -E "(module|replace)" -A1
♻️ Duplicate comments (10)
client-go/version/version.go (1)

15-15: Add package-level godoc comment.

The coding guidelines require package-level godoc for all Go packages. A package comment describing the purpose of this package is still missing.

As per coding guidelines, package-level godoc is required for all Go packages.

client-go/nvgrpc/client_conn_test.go (1)

23-57: Use testify for assertions as required by coding guidelines.

The tests use stdlib t.Fatalf/t.Error instead of testify/require and testify/assert. This was flagged in a previous review and should be addressed.

🔎 Example refactor using testify
 import (
 	"testing"
 
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 	"github.com/go-logr/logr"
 )
 
 func TestClientConnFor(t *testing.T) {
 	t.Run("Config defaulting does not mutate original", func(t *testing.T) {
 		cfg := &Config{}
 		conn, err := ClientConnFor(cfg)
-		if err != nil {
-			t.Fatalf("unexpected error: %v", err)
-		}
+		require.NoError(t, err)
+		require.NotNil(t, conn)
 		defer conn.Close()
 
-		if cfg.Target != "" {
-			t.Errorf("Original config was mutated! Target is %q", cfg.Target)
-		}
+		assert.Empty(t, cfg.Target, "Original config should not be mutated")
 	})
 
 	t.Run("Config.Default() works correctly", func(t *testing.T) {
 		cfg := &Config{}
 		cfg.Default()
 
-		if cfg.Target == "" {
-			t.Error("Target was not defaulted")
-		}
-		if cfg.UserAgent == "" {
-			t.Error("UserAgent was not defaulted")
-		}
+		assert.NotEmpty(t, cfg.Target, "Target should be defaulted")
+		assert.NotEmpty(t, cfg.UserAgent, "UserAgent should be defaulted")
 	})
 
 	t.Run("Client creation respects WithLogger option", func(t *testing.T) {
 		cfg := &Config{Target: "unix:///tmp/test.sock"}
 		conn, err := ClientConnFor(cfg, WithLogger(logr.Discard()))
-		if err != nil {
-			t.Fatalf("failed to create client: %v", err)
-		}
+		require.NoError(t, err)
+		require.NotNil(t, conn)
 		conn.Close()
 	})
 }

Based on coding guidelines.

client-go/examples/fake-server/main.go (1)

181-194: Populate ListMeta.ResourceVersion for List-then-Watch semantics.

The GpuList response doesn't include Metadata.ResourceVersion, which clients need to establish a consistent Watch point. This was flagged in a previous review.

🔎 Suggested fix
+func (s *fakeServer) ListGpus(ctx context.Context, req *pb.ListGpusRequest) (*pb.ListGpusResponse, error) {
+	s.mu.RLock()
+	defer s.mu.RUnlock()
+
+	// Determine the highest resource version across all GPUs
+	maxRV := "0"
+	for _, gpu := range s.gpus {
+		if gpu.ResourceVersion > maxRV {
+			maxRV = gpu.ResourceVersion
+		}
+	}
+
 	gpuList := &pb.GpuList{
+		Metadata: &pb.ListMeta{
+			ResourceVersion: maxRV,
+		},
 		Items: make([]*pb.Gpu, 0, len(s.gpus)),
 	}
 
 	for _, gpu := range s.gpus {
 		gpuList.Items = append(gpuList.Items, devicev1alpha1.ToProto(&gpu))
 	}
 
 	return &pb.ListGpusResponse{GpuList: gpuList}, nil
 }
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1)

37-44: Validate the config in NewForConfigAndClient.

The past review comment correctly identified that NewForConfigAndClient doesn't validate the config before using it. While the config is primarily used for logger extraction, adding validation would ensure consistency with the NewForConfig path.

api/proto/device/v1alpha1/gpu.proto (1)

27-51: Fix inconsistent indentation in comment blocks.

Lines 35-37 use tabs while surrounding lines use spaces, creating inconsistent formatting. This was flagged in a previous review.

🔎 Suggested fix
   // resource_version represents the internal version of this object.
   //
   // Value must be treated as opaque by clients and passed unmodified back to the server.
-	// Populated by the system.
-	// Read-only.
-	// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
+  // Populated by the system.
+  // Read-only.
+  // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
   string resource_version = 2;
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (2)

1-11: Add package-level godoc comment.

The coding guidelines require package-level documentation for all Go packages. This was previously flagged and appears unaddressed.

As per coding guidelines.

🔎 Suggested documentation
+// Package fake provides fake implementations of the device v1alpha1 client
+// for testing purposes. These fakes use an in-memory ObjectTracker instead
+// of actual gRPC connections.
 package fake

13-15: Add function comment for exported method.

The coding guidelines require function comments for all exported Go functions. This was previously flagged.

As per coding guidelines.

🔎 Suggested documentation
+// GPUs returns a fake GPUInterface for testing GPU operations
+// without requiring an actual gRPC connection.
 func (c *FakeDeviceV1alpha1) GPUs() v1alpha1.GPUInterface {
 	return newFakeGPUs(c)
 }
client-go/examples/controller-shim/main.go (1)

58-62: The informer factory is never started.

The comment on line 60 states the Manager will start the injected informer, but controller-runtime only starts informers created through its own cache machinery. The gRPC-backed informer from factory needs to be started explicitly; otherwise, the cache will never populate and reconciliation won't occur.

🔎 Suggested fix
 	factory := informers.NewSharedInformerFactory(clientset, 10*time.Minute)
 	gpuInformer := factory.Device().V1alpha1().GPUs().Informer()

+	// Start the factory in a background goroutine before the manager starts.
+	stopCh := make(chan struct{})
+	go factory.Start(stopCh)
+
 	// Initialize the controller-runtime Manager.

Then ensure stopCh is closed on shutdown (e.g., via defer close(stopCh) after manager setup, or tie it to the signal handler context).

client-go/hack/overlays/client/versioned/integration_test.go (1)

210-214: Avoid calling t.Errorf from a goroutine.

Calling t.Errorf (or any t method) from a goroutine is unsafe and can cause race conditions or panics if the test completes before the goroutine executes.

🔎 Suggested fix using an error channel
+		errCh := make(chan error, 1)
 		go func() {
 			if err := c.Start(ctx); err != nil {
-				t.Errorf("Cache failed to start: %v", err)
+				errCh <- err
 			}
+			close(errCh)
 		}()

Alternatively, since c.Start blocks until context cancellation and typically only returns errors on shutdown, you could log the error or use t.Log for informational purposes, as the cache sync check will catch initialization failures.

client-go/Makefile (1)

187-187: Declare tools target as .PHONY.

The tools target should be declared .PHONY since it doesn't produce a file and is used as a convenience alias for tool binaries.

🔎 Proposed fix
+.PHONY: tools
 tools: $(CLIENT_GEN) $(LISTER_GEN) $(INFORMER_GEN)

As per static analysis hint.

🧹 Nitpick comments (10)
client-go/version/version_test.go (1)

9-19: Consider a more descriptive test name.

While the test logic is correct and properly handles the package-level variable modification, consider naming it following the guideline format: TestUserAgent_WithCustomVersion_ReturnsFormattedString for better clarity.

As per coding guidelines, test names should follow the format: TestFunctionName_Scenario_ExpectedBehavior.

🔎 Optional improvement
-func TestUserAgent(t *testing.T) {
+func TestUserAgent_WithCustomVersion_ReturnsFormattedString(t *testing.T) {
api/device/v1alpha1/register.go (1)

25-27: Add godoc comment for exported function.

The exported Resource function lacks documentation explaining its purpose in mapping resource names to GroupResource.

As per coding guidelines.

🔎 Suggested documentation
+// Resource takes an unqualified resource and returns a GroupResource with the correct group.
 func Resource(resource string) schema.GroupResource {
 	return SchemeGroupVersion.WithResource(resource).GroupResource()
 }
client-go/nvgrpc/client_conn.go (1)

25-26: Godoc should mention insecure transport.

The function uses insecure.NewCredentials() (line 44) for Unix domain sockets, but the documentation doesn't clarify that TLS is not enabled. Consider noting this is suitable for local/trusted connections.

🔎 Suggested documentation
-// ClientConnFor creates a new gRPC connection using the provided configuration and options.
+// ClientConnFor creates a new gRPC connection using the provided configuration and options.
+// It uses insecure transport credentials suitable for Unix domain sockets and local connections.
client-go/hack/overlays/client/versioned/clientset.go (1)

46-65: Consider validating config in NewForConfigAndClient.

While the nil check is present, the config content isn't validated. Since nvgrpc.ClientConnFor isn't called in this path, invalid config values could propagate to the device client creation.

🔎 Proposed validation addition
 func NewForConfigAndClient(c *nvgrpc.Config, conn grpc.ClientConnInterface) (*Clientset, error) {
 	if c == nil {
 		return nil, fmt.Errorf("config cannot be nil")
 	}
+	if err := c.Validate(); err != nil {
+		return nil, err
+	}
 	if conn == nil {
 		return nil, fmt.Errorf("gRPC connection cannot be nil")
 	}
client-go/nvgrpc/options_test.go (1)

25-65: LGTM: Comprehensive option testing.

The test validates logger assignment and interceptor appending, including multiple interceptors. The use of subtests improves test organization.

While the current assertions work, consider using testify/assert for more descriptive failure messages in future tests, per coding guidelines.

client-go/nvgrpc/config_test.go (1)

20-120: Well-structured tests with comprehensive coverage.

The table-driven tests effectively cover Target precedence, UserAgent defaults, and validation logic. The use of t.Setenv() for environment variable testing is correct.

Optional: Consider using testify for assertions

Per coding guidelines, you may want to use testify/assert or testify/require for cleaner assertions:

+import (
+	"testing"
+	"github.com/stretchr/testify/require"
+)

 func TestConfig_Default_TargetPrecedence(t *testing.T) {
 	// ... test table ...
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			t.Setenv(NvidiaDeviceAPITargetEnvVar, tt.envTarget)
 			cfg := &Config{Target: tt.argTarget}
 			cfg.Default()
-			if cfg.Target != tt.wantTarget {
-				t.Errorf("Target = %q, want %q", cfg.Target, tt.wantTarget)
-			}
+			require.Equal(t, tt.wantTarget, cfg.Target)
 		})
 	}
 }

However, the current implementation is also acceptable.

api/device/v1alpha1/gpu_conversion_test.go (1)

30-153: Solid conversion tests with good nil-safety and round-trip verification.

The tests correctly use protocmp.Transform() for protobuf comparisons and verify key behaviors like Name lowercasing and ResourceVersion propagation.

Optional: More descriptive test names per coding guidelines

Per the coding guideline "Name Go tests descriptively using format: TestFunctionName_Scenario_ExpectedBehavior", consider renaming:

-func TestGPUConversion(t *testing.T) {
+func TestGPUConversion_RoundTrip_PreservesMetadataAndFields(t *testing.T) {

-func TestGPUListConversion(t *testing.T) {
+func TestGPUListConversion_RoundTrip_PreservesListMetadataAndItems(t *testing.T) {

This makes the test intent more explicit at a glance.

client-go/DEVELOPMENT.md (1)

77-77: Minor style improvement.

The phrase "inside of" is redundant. Simply "inside" is preferred.

-The directory structure inside of `hack/overlays/` **must exactly mirror** the structure of the generated code.
+The directory structure inside `hack/overlays/` **must exactly mirror** the structure of the generated code.
client-go/nvgrpc/interceptors_test.go (1)

29-66: Remove unused expectedCode field from test struct.

The expectedCode field (line 35) is defined in the test cases but never used in assertions. This is dead code that may confuse future maintainers.

🔎 Suggested fix
 	tests := []struct {
 		name         string
 		method       string
 		log          bool
 		invokerErr   error
-		expectedCode codes.Code
 	}{
-		{"Returns OK code for successful call", "/svc/success", true, nil, codes.OK},
-		{"Returns internal status error on internal error", "/svc/internal_error", true, status.Error(codes.Internal, "fail"), codes.Internal},
-		{"Returns canceled status error when canceled", "/svc/cancel", true, status.Error(codes.Canceled, ""), codes.Canceled},
-		{"Returns deadline exceeded status error on timeout", "/svc/timeout", true, status.Error(codes.DeadlineExceeded, ""), codes.DeadlineExceeded},
-		{"Does not log if level too low", "/svc/skip_log", false, nil, codes.OK},
+		{"Returns OK code for successful call", "/svc/success", true, nil},
+		{"Returns internal status error on internal error", "/svc/internal_error", true, status.Error(codes.Internal, "fail")},
+		{"Returns canceled status error when canceled", "/svc/cancel", true, status.Error(codes.Canceled, "")},
+		{"Returns deadline exceeded status error on timeout", "/svc/timeout", true, status.Error(codes.DeadlineExceeded, "")},
+		{"Does not log if level too low", "/svc/skip_log", false, nil},
 	}

This also allows removing the codes import if it becomes unused.

client-go/nvgrpc/watcher_test.go (1)

31-177: Good test coverage, consider using testify for assertions.

The tests comprehensively cover normal operation, error handling, and lifecycle management. Test structure and naming are clear.

Consider adopting testify/assert and testify/require for more expressive assertions, as per coding guidelines. For example:

import (
    "github.com/stretchr/testify/assert"
    "github.com/stretchr/testify/require"
)

// Instead of:
if len(got) != len(wantTypes) {
    t.Fatalf("got %d events, want %d", len(got), len(wantTypes))
}

// Use:
require.Len(t, got, len(wantTypes), "unexpected event count")
assert.Equal(t, wantTypes[i], ev.Type, "event %d type mismatch", i)

As per coding guidelines, prefer testify for test assertions.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ef820c3 and 1072d57.

⛔ Files ignored due to path filters (28)
  • api/device/v1alpha1/zz_generated.conversion.go is excluded by !api/**/zz_generated.*
  • api/device/v1alpha1/zz_generated.deepcopy.go is excluded by !api/**/zz_generated.*
  • api/gen/go/device/v1alpha1/gpu.pb.go is excluded by !**/*.pb.go, !**/gen/**, !api/gen/**
  • api/go.sum is excluded by !**/*.sum
  • client-go/client/versioned/clientset.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/clientset_generated.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/register.go is excluded by !client-go/client/**
  • client-go/client/versioned/integration_test.go is excluded by !client-go/client/**
  • client-go/client/versioned/scheme/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/scheme/register.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/device_client.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_gpu.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/generated_expansion.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/gpu.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go is excluded by !client-go/client/**
  • client-go/go.sum is excluded by !**/*.sum
  • client-go/informers/externalversions/device/interface.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/device/v1alpha1/gpu.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/device/v1alpha1/interface.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/factory.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/generic.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go is excluded by !client-go/informers/**
  • client-go/listers/device/v1alpha1/expansion_generated.go is excluded by !client-go/listers/**
  • client-go/listers/device/v1alpha1/gpu.go is excluded by !client-go/listers/**
📒 Files selected for processing (47)
  • .coderabbit.yaml (1 hunks)
  • .gitignore (1 hunks)
  • .versions.yaml (1 hunks)
  • api/Makefile (5 hunks)
  • api/device/v1alpha1/converter.go (1 hunks)
  • api/device/v1alpha1/doc.go (1 hunks)
  • api/device/v1alpha1/gpu_conversion.go (1 hunks)
  • api/device/v1alpha1/gpu_conversion_test.go (1 hunks)
  • api/device/v1alpha1/gpu_types.go (1 hunks)
  • api/device/v1alpha1/register.go (1 hunks)
  • api/go.mod (2 hunks)
  • api/hack/boilerplate.go.txt (1 hunks)
  • api/proto/device/v1alpha1/gpu.proto (4 hunks)
  • client-go/DEVELOPMENT.md (1 hunks)
  • client-go/Makefile (1 hunks)
  • client-go/README.md (1 hunks)
  • client-go/examples/README.md (1 hunks)
  • client-go/examples/basic-client/README.md (1 hunks)
  • client-go/examples/basic-client/main.go (1 hunks)
  • client-go/examples/controller-shim/README.md (1 hunks)
  • client-go/examples/controller-shim/main.go (1 hunks)
  • client-go/examples/fake-server/README.md (1 hunks)
  • client-go/examples/fake-server/main.go (1 hunks)
  • client-go/examples/streaming-daemon/README.md (1 hunks)
  • client-go/examples/streaming-daemon/main.go (1 hunks)
  • client-go/go.mod (1 hunks)
  • client-go/hack/apply-overlays.sh (1 hunks)
  • client-go/hack/boilerplate.go.txt (1 hunks)
  • client-go/hack/boilerplate_overlay.go.txt (1 hunks)
  • client-go/hack/overlays/client/versioned/clientset.go (1 hunks)
  • client-go/hack/overlays/client/versioned/integration_test.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1 hunks)
  • client-go/nvgrpc/client_conn.go (1 hunks)
  • client-go/nvgrpc/client_conn_test.go (1 hunks)
  • client-go/nvgrpc/config.go (1 hunks)
  • client-go/nvgrpc/config_test.go (1 hunks)
  • client-go/nvgrpc/interceptors.go (1 hunks)
  • client-go/nvgrpc/interceptors_test.go (1 hunks)
  • client-go/nvgrpc/options.go (1 hunks)
  • client-go/nvgrpc/options_test.go (1 hunks)
  • client-go/nvgrpc/watcher.go (1 hunks)
  • client-go/nvgrpc/watcher_test.go (1 hunks)
  • client-go/version/version.go (1 hunks)
  • client-go/version/version_test.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.go: Follow standard Go conventions with gofmt and golint
Use structured logging via log/slog in Go code
Wrap errors with context using fmt.Errorf("context: %w", err) in Go code
Within retry.RetryOnConflict blocks, return errors without wrapping to preserve retry behavior
Use meaningful variable names such as synced over ok for cache sync checks
Use client-go for Kubernetes API interactions in Go code
Prefer informers over direct API calls for watching Kubernetes resources
Implement proper shutdown handling with context cancellation in Go code
Package-level godoc required for all Go packages
Function comments required for all exported Go functions
Use inline comments for complex logic only in Go code
TODO comments should reference issues in Go code
Extract informer event handler setup into helper methods
Use separate informers for different Kubernetes resource types

Files:

  • client-go/version/version.go
  • api/device/v1alpha1/register.go
  • client-go/nvgrpc/options_test.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/examples/streaming-daemon/main.go
  • client-go/nvgrpc/interceptors.go
  • client-go/examples/basic-client/main.go
  • client-go/nvgrpc/client_conn_test.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go
  • client-go/nvgrpc/config_test.go
  • client-go/examples/fake-server/main.go
  • client-go/nvgrpc/client_conn.go
  • api/device/v1alpha1/gpu_conversion_test.go
  • client-go/nvgrpc/interceptors_test.go
  • client-go/version/version_test.go
  • client-go/nvgrpc/options.go
  • api/device/v1alpha1/doc.go
  • client-go/nvgrpc/watcher.go
  • client-go/nvgrpc/config.go
  • api/device/v1alpha1/converter.go
  • client-go/examples/controller-shim/main.go
  • api/device/v1alpha1/gpu_conversion.go
  • client-go/hack/overlays/client/versioned/clientset.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • api/device/v1alpha1/gpu_types.go
  • client-go/nvgrpc/watcher_test.go
**/*_test.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*_test.go: Use envtest for testing Kubernetes controllers instead of fake clients
Use testify/assert and testify/require for assertions in Go tests
Write table-driven tests when testing multiple scenarios in Go
Name Go tests descriptively using format: TestFunctionName_Scenario_ExpectedBehavior

Files:

  • client-go/nvgrpc/options_test.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/nvgrpc/client_conn_test.go
  • client-go/nvgrpc/config_test.go
  • api/device/v1alpha1/gpu_conversion_test.go
  • client-go/nvgrpc/interceptors_test.go
  • client-go/version/version_test.go
  • client-go/nvgrpc/watcher_test.go
**/go.mod

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use go.mod for each service as a separate Go module with semantic import versioning

Files:

  • client-go/go.mod
  • api/go.mod
🧠 Learnings (22)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Keep Go dependencies minimal and up-to-date

Applied to files:

  • .versions.yaml
  • client-go/go.mod
  • api/go.mod
  • api/Makefile
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code

Applied to files:

  • .versions.yaml
  • client-go/examples/basic-client/README.md
  • client-go/examples/basic-client/main.go
  • client-go/nvgrpc/client_conn_test.go
  • client-go/hack/boilerplate_overlay.go.txt
  • client-go/go.mod
  • client-go/README.md
  • api/go.mod
  • client-go/hack/apply-overlays.sh
  • client-go/examples/README.md
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/Makefile
  • client-go/DEVELOPMENT.md
  • .gitignore
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Use `envtest` for testing Kubernetes controllers instead of fake clients

Applied to files:

  • .versions.yaml
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/nvgrpc/client_conn_test.go
  • client-go/go.mod
  • client-go/version/version_test.go
  • client-go/examples/README.md
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • .gitignore
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Follow standard Go conventions with gofmt and golint

Applied to files:

  • .versions.yaml
  • .gitignore
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: All files must include Apache 2.0 license header

Applied to files:

  • api/hack/boilerplate.go.txt
  • client-go/hack/boilerplate_overlay.go.txt
  • client-go/hack/boilerplate.go.txt
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : TODO comments should reference issues in Go code

Applied to files:

  • client-go/version/version.go
  • client-go/nvgrpc/client_conn_test.go
  • client-go/go.mod
  • client-go/nvgrpc/options.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Package-level godoc required for all Go packages

Applied to files:

  • client-go/version/version.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Function comments required for all exported Go functions

Applied to files:

  • client-go/version/version.go
  • client-go/nvgrpc/options.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use meaningful variable names such as `synced` over `ok` for cache sync checks

Applied to files:

  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/examples/controller-shim/main.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Implement proper shutdown handling with context cancellation in Go code

Applied to files:

  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/nvgrpc/watcher.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Use `testify/assert` and `testify/require` for assertions in Go tests

Applied to files:

  • client-go/nvgrpc/client_conn_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Write table-driven tests when testing multiple scenarios in Go

Applied to files:

  • client-go/nvgrpc/client_conn_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Name Go tests descriptively using format: `TestFunctionName_Scenario_ExpectedBehavior`

Applied to files:

  • client-go/nvgrpc/client_conn_test.go
  • api/device/v1alpha1/gpu_conversion_test.go
  • client-go/version/version_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Aim for >80% test coverage on critical paths in Go code

Applied to files:

  • client-go/nvgrpc/client_conn_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/go.mod : Use `go.mod` for each service as a separate Go module with semantic import versioning

Applied to files:

  • client-go/go.mod
  • api/go.mod
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Prefer informers over direct API calls for watching Kubernetes resources

Applied to files:

  • client-go/go.mod
  • client-go/nvgrpc/watcher.go
  • api/go.mod
  • client-go/examples/controller-shim/main.go
📚 Learning: 2025-12-01T17:53:20.067Z
Learnt from: jtschelling
Repo: NVIDIA/NVSentinel PR: 455
File: docs/designs/013-remediation-plugins.md:162-204
Timestamp: 2025-12-01T17:53:20.067Z
Learning: Code examples in design documents (docs/designs/) in the NVSentinel repository are illustrative stubs meant to show intent and architectural concepts, and do not need to be 100% correct or complete implementations (e.g., undefined variables, missing error handling, incomplete struct initialization are acceptable).

Applied to files:

  • api/go.mod
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use separate informers for different Kubernetes resource types

Applied to files:

  • client-go/examples/controller-shim/main.go
📚 Learning: 2025-11-04T06:31:02.147Z
Learnt from: Gyan172004
Repo: NVIDIA/NVSentinel PR: 223
File: platform-connectors/pkg/nodemetadata/processor.go:0-0
Timestamp: 2025-11-04T06:31:02.147Z
Learning: In platform-connectors/pkg/nodemetadata/processor.go, the NewProcessor function does not perform a nil check on the config parameter because the caller is expected to guarantee a non-nil config is provided.

Applied to files:

  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to data-models/protobufs/**/*.proto : Include comprehensive comments for all fields in Protocol Buffer messages

Applied to files:

  • api/proto/device/v1alpha1/gpu.proto
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to data-models/protobufs/**/*.proto : Use semantic versioning for breaking changes in Protocol Buffer messages

Applied to files:

  • api/proto/device/v1alpha1/gpu.proto
🧬 Code graph analysis (18)
api/device/v1alpha1/register.go (1)
api/device/v1alpha1/gpu_types.go (2)
  • GPU (55-61)
  • GPUList (67-71)
client-go/nvgrpc/options_test.go (1)
client-go/nvgrpc/options.go (4)
  • DialOption (23-23)
  • WithLogger (32-36)
  • WithUnaryInterceptor (39-43)
  • WithStreamInterceptor (46-50)
client-go/hack/overlays/client/versioned/integration_test.go (4)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/hack/overlays/client/versioned/clientset.go (2)
  • NewForConfigAndClient (48-65)
  • New (79-83)
api/device/v1alpha1/gpu_types.go (1)
  • GPU (55-61)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1)
api/device/v1alpha1/gpu_conversion.go (1)
  • FromProto (25-32)
client-go/nvgrpc/config_test.go (2)
client-go/nvgrpc/config.go (3)
  • DefaultNvidiaDeviceAPISocket (31-31)
  • NvidiaDeviceAPITargetEnvVar (28-28)
  • Config (41-49)
client-go/version/version.go (1)
  • UserAgent (28-35)
client-go/nvgrpc/client_conn.go (4)
client-go/nvgrpc/config.go (3)
  • Config (41-49)
  • DefaultKeepAliveTime (34-34)
  • DefaultKeepAliveTimeout (37-37)
client-go/nvgrpc/options.go (1)
  • DialOption (23-23)
client-go/version/version.go (1)
  • UserAgent (28-35)
client-go/nvgrpc/interceptors.go (2)
  • NewLatencyUnaryInterceptor (28-59)
  • NewLatencyStreamInterceptor (62-92)
api/device/v1alpha1/gpu_conversion_test.go (1)
api/device/v1alpha1/gpu_conversion.go (4)
  • FromProto (25-32)
  • ToProto (35-40)
  • FromProtoList (43-48)
  • ToProtoList (51-56)
client-go/nvgrpc/interceptors_test.go (1)
client-go/nvgrpc/interceptors.go (2)
  • NewLatencyUnaryInterceptor (28-59)
  • NewLatencyStreamInterceptor (62-92)
client-go/version/version_test.go (1)
client-go/version/version.go (2)
  • GitVersion (25-25)
  • UserAgent (28-35)
client-go/nvgrpc/config.go (1)
client-go/version/version.go (1)
  • UserAgent (28-35)
api/device/v1alpha1/converter.go (2)
api/device/v1alpha1/gpu_types.go (4)
  • GPU (55-61)
  • GPUList (67-71)
  • GPUSpec (24-30)
  • GPUStatus (35-45)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
client-go/examples/controller-shim/main.go (5)
client-go/hack/overlays/client/versioned/clientset.go (2)
  • New (79-83)
  • NewForConfig (32-44)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (2)
  • New (58-63)
  • NewForConfig (27-35)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
api/device/v1alpha1/gpu_types.go (1)
  • GPU (55-61)
api/device/v1alpha1/gpu_conversion.go (2)
api/device/v1alpha1/converter.go (1)
  • Converter (30-104)
api/device/v1alpha1/gpu_types.go (2)
  • GPU (55-61)
  • GPUList (67-71)
client-go/hack/overlays/client/versioned/clientset.go (3)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (6)
  • DeviceV1alpha1Interface (9-12)
  • DeviceV1alpha1Client (15-18)
  • NewForConfig (27-35)
  • NewForConfigAndClient (39-44)
  • NewForConfigOrDie (48-55)
  • New (58-63)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/nvgrpc/client_conn.go (1)
  • ClientConnFor (26-72)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (4)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (2)
  • GPUsGetter (17-19)
  • GPUInterface (22-27)
client-go/hack/overlays/client/versioned/clientset.go (3)
  • NewForConfig (32-44)
  • NewForConfigAndClient (48-65)
  • New (79-83)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/nvgrpc/client_conn.go (1)
  • ClientConnFor (26-72)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (5)
api/device/v1alpha1/gpu_types.go (2)
  • GPU (55-61)
  • GPUList (67-71)
client-go/hack/overlays/client/versioned/clientset.go (1)
  • Interface (12-14)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1)
  • DeviceV1alpha1Client (15-18)
api/device/v1alpha1/gpu_conversion.go (2)
  • FromProto (25-32)
  • FromProtoList (43-48)
client-go/nvgrpc/watcher.go (1)
  • NewWatcher (49-64)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (1)
  • GPUInterface (22-27)
client-go/nvgrpc/watcher_test.go (1)
client-go/nvgrpc/watcher.go (1)
  • NewWatcher (49-64)
🪛 checkmake (0.2.2)
client-go/Makefile

[warning] 187-187: Target "tools" should be declared PHONY.

(phonydeclared)

🪛 GitHub Actions: Lint and Test
client-go/go.mod

[error] 1-1: gomod-lint failed: Invalid module version for github.com/nvidia/nvsentinel/api. Current: v0.0.0-00010101000000-000000000000; Expected: v0.0.0. Local modules should use v0.0.0 (no timestamp).

api/go.mod

[error] 1-1: Command failed: make gomod-lint. gomod-lint reported incorrect version for github.com/nvidia/nvsentinel/api: Current: v0.0.0-00010101000000-000000000000, Expected: v0.0.0. Local modules should use v0.0.0 (no timestamp).

api/Makefile

[error] 1-1: License header linting failed. Command 'make license-headers-lint' exited with code 2.

client-go/Makefile

[error] 1-1: License header linting failed. Command 'make license-headers-lint' exited with code 2.

🪛 LanguageTool
client-go/DEVELOPMENT.md

[style] ~77-~77: This phrase is redundant. Consider using “inside”.
Context: ... informers/) The directory structure inside of hack/overlays/ *must exactly mirror...

(OUTSIDE_OF)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: E2E Tests (AMD64 + PostgreSQL)
  • GitHub Check: E2E Tests (AMD64 + MongoDB)
  • GitHub Check: E2E Tests (ARM64 + MongoDB)
🔇 Additional comments (49)
.gitignore (1)

18-18: Consistent and appropriate addition.

The new entry client-go/bin/* correctly mirrors the existing api/bin/* pattern and aligns with the PR's introduction of a new client-go module with generated code and build artifacts. The placement within the Go section is logical and follows established conventions.

client-go/hack/boilerplate.go.txt (1)

1-13: ✓ Correct Apache 2.0 license header boilerplate.

The boilerplate template is well-formed, uses proper Go comment syntax, includes the current year (2025) in the copyright notice, and provides the complete Apache 2.0 license text with correct URL and disclaimers. This file will serve correctly as a template for prepending license headers to generated code.

api/hack/boilerplate.go.txt (1)

1-13: LGTM!

The Apache 2.0 license header is correctly formatted and will serve as the boilerplate template for code generation tools.

.coderabbit.yaml (1)

19-24: LGTM!

The path filters correctly exclude generated code from review (protobuf bindings, deepcopy/conversion code, generated clientsets, listers, and informers). This aligns with the PR's code generation strategy and follows best practices.

client-go/examples/basic-client/README.md (1)

1-28: LGTM!

The README provides clear, comprehensive documentation for the basic client reference implementation. The structure, content, and examples are well-organized and align with the PR's objectives.

client-go/examples/README.md (1)

1-38: LGTM!

The examples README provides an excellent overview with a well-structured table categorizing examples by complexity and focus. The prerequisites and running instructions are clear and complete.

client-go/examples/fake-server/README.md (1)

1-18: LGTM!

The fake server README clearly documents its purpose, usage, and behavior. The explanation of the 2-second status toggle is particularly useful for understanding how Watch streams and controllers can be tested locally.

client-go/version/version.go (1)

22-35: LGTM!

The GitVersion variable and UserAgent function are well-documented and correctly implemented. The build-time override pattern using ldflags is clearly explained and follows standard Go practices.

client-go/nvgrpc/interceptors.go (2)

27-59: LGTM: Well-structured unary interceptor.

The latency interceptor correctly measures RPC duration, propagates errors, and uses appropriate verbosity levels for different scenarios.


61-92: LGTM: Stream interceptor follows the same pattern.

The stream interceptor mirrors the unary pattern with appropriate verbosity thresholds for stream establishment.

client-go/nvgrpc/options.go (1)

22-50: LGTM: Clean functional options implementation.

The DialOption pattern is correctly implemented with clear documentation for all exported functions. The interceptor appending allows proper chaining.

client-go/nvgrpc/config.go (1)

26-89: LGTM: Robust configuration with proper defaults.

The Config implementation correctly:

  • Documents all exported constants and types
  • Uses environment variables for flexibility
  • Provides safe defaults including a discard logger
  • Validates required fields with clear error messages
client-go/nvgrpc/client_conn.go (1)

27-71: LGTM: Correct implementation with proper isolation.

The function correctly:

  • Creates a shallow copy to avoid mutating the caller's Config
  • Applies dial options and defaults
  • Validates configuration before dialing
  • Builds interceptor chains with latency monitoring first
  • Wraps errors with context
client-go/examples/fake-server/main.go (2)

40-82: LGTM: Clean server setup with proper shutdown handling.

The main function correctly:

  • Reads socket path from environment with sensible default
  • Removes stale sockets before listening
  • Registers signal handlers for graceful shutdown
  • Cleans up socket on exit

196-246: LGTM: WatchGpus correctly implements streaming pattern.

The watch implementation:

  • Sends initial ADDED events for all GPUs under lock
  • Registers listener for future updates
  • Properly cleans up listener on stream close
  • Handles context cancellation correctly
client-go/examples/streaming-daemon/README.md (1)

1-30: LGTM: Clear documentation for streaming patterns.

The README effectively documents:

  • Production-grade patterns for long-lived connections
  • Key concepts (manual connection management, interceptors, stream processing, context handling)
  • Running instructions with correct path to fake-server
  • Expected output matching the fake-server implementation
client-go/hack/overlays/client/versioned/clientset.go (3)

26-44: LGTM: Proper config validation and shallow copy.

The nil check, shallow copy to prevent mutation, and delegation to nvgrpc.ClientConnFor (which validates the config) follow the correct pattern.


67-76: LGTM: Standard OrDie pattern.

The panic-on-error behavior is appropriate for this constructor variant.


78-83: LGTM: Direct connection constructor.

The implementation correctly creates a clientset from an existing connection, with logging disabled by default.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (4)

9-12: LGTM: Clean interface definition.

The interface correctly defines the contract for the v1alpha1 device client.


24-35: LGTM: Proper delegation with validated config.

The shallow copy and validation via nvgrpc.ClientConnFor are correct.


46-55: LGTM: Standard OrDie pattern.

The panic-on-error behavior is appropriate for this constructor variant.


65-73: LGTM: Defensive nil check in accessor.

The nil check on the receiver prevents potential panics and follows defensive programming practices.

client-go/hack/boilerplate_overlay.go.txt (1)

1-16: LGTM: Proper boilerplate header.

The Apache 2.0 license header and generated code notice are correctly formatted.

client-go/examples/controller-shim/README.md (1)

1-42: LGTM: Clear and comprehensive documentation.

The README effectively explains the hybrid reconciliation pattern, informer injection, and controller-runtime integration. The running instructions and expected output are helpful for users.

client-go/hack/apply-overlays.sh (1)

1-29: LGTM: Robust error handling and clear logic.

The script correctly uses set -euo pipefail, validates prerequisites, and processes overlays with proper path manipulation. The addressed past review comment about error handling has been resolved.

api/device/v1alpha1/doc.go (1)

15-19: LGTM: Proper API group documentation.

The Kubebuilder marker and package documentation correctly define the v1alpha1 API group with clear descriptions of GPU resources and conversion functions.

client-go/examples/basic-client/main.go (1)

30-80: Clean example demonstrating basic client usage.

The example effectively shows List, Get, and condition inspection patterns. Good use of meta.IsStatusConditionTrue() for checking conditions and proper error handling throughout.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1)

9-27: Clean adapter implementation for gRPC stream to runtime.Object conversion.

The adapter correctly delegates to the underlying stream for Recv() and CloseSend(), and uses FromProto() for type conversion. The nil-handling is safe since FromProto() already checks for nil input.

client-go/DEVELOPMENT.md (1)

1-105: Comprehensive and well-organized development guide.

The documentation clearly explains the code generation workflow, overlay pattern, and housekeeping commands. The Mermaid diagram effectively visualizes the generation pipeline.

client-go/README.md (1)

1-96: Excellent documentation for the client-go SDK.

The README provides clear explanations of features, installation, quick start examples, and deployment patterns. The warning about experimental status is appropriately prominent, and the examples table effectively guides users to the right integration pattern.

client-go/examples/streaming-daemon/main.go (1)

36-144: Excellent demonstration of advanced gRPC patterns.

The example effectively showcases custom interceptors for tracing and monitoring, manual connection lifecycle management, and comprehensive watch stream handling including error cases and context timeouts. Good use of defer for cleanup and proper channel handling.

api/device/v1alpha1/gpu_conversion.go (1)

15-56: Well-designed conversion helper layer.

The helpers provide a clean public API with proper nil-safety. The build tag !goverter correctly excludes this file during code generation, and the pointer handling differences between FromProto and FromProtoList correctly match the underlying converter interface signatures.

client-go/go.mod (1)

1-15: Module structure looks good.

The module declaration, Go version, replace directive, and direct dependencies are well-organized. The Kubernetes dependency versions are aligned at v0.34.1, and the controller-runtime version is appropriate.

client-go/nvgrpc/interceptors_test.go (1)

68-103: LGTM!

The streaming interceptor test is well-structured with appropriate coverage of success, error, and log-level gating scenarios. The error propagation assertion using errors.Is is correct.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1)

17-24: LGTM on ClientConn implementation.

The ClientConn() method is appropriately documented, explaining that the fake uses ObjectTracker instead of a real gRPC connection. Returning nil is acceptable here since the fake implementation doesn't need an actual connection.

client-go/examples/controller-shim/main.go (2)

64-105: Manager configuration is well-designed for hybrid reconciliation.

The custom MapperProvider correctly registers GPU as a root-scoped resource, and the NewInformer callback appropriately injects the gRPC-backed informer for GPU objects while falling back to standard informers for other types. The indexer merging logic correctly handles conflicts.


123-145: LGTM!

The GPUReconciler follows controller-runtime best practices: proper structured logging, graceful NotFound handling with client.IgnoreNotFound, and standard controller builder pattern in SetupWithManager.

client-go/hack/overlays/client/versioned/integration_test.go (3)

33-63: Well-structured test harness setup.

The test correctly sets up an in-process gRPC server using bufconn, creates a mock GPU server, and establishes a clientset connection. This pattern enables fast, isolated integration testing without network overhead.


64-129: LGTM on Get, List, and Watch tests.

The subtests properly exercise the core clientset operations with appropriate assertions and timeout handling. The Watch test correctly validates both initial snapshot and live event propagation.


255-337: LGTM on mock server implementation.

The mock server is well-designed with proper thread-safety using sync.RWMutex, correct context handling in the streaming WatchGpus method, and a clean sendEvent helper for test control. The initial snapshot followed by live event streaming correctly mimics Kubernetes watch semantics.

api/proto/device/v1alpha1/gpu.proto (2)

53-78: LGTM on Gpu and GpuList message structure.

The restructured messages follow the Kubernetes Resource Model pattern correctly with ObjectMeta/ListMeta at field 1, and the documentation clearly explains the naming conventions. This aligns well with client-go expectations.


151-167: LGTM on request message updates.

Adding resource_version to ListGpusRequest and WatchGpusRequest enables proper Kubernetes-style watch semantics, allowing clients to list/watch from a specific version and resume watches after disconnection.

api/device/v1alpha1/gpu_types.go (1)

15-71: LGTM! Well-structured Kubernetes CRD types.

The GPU resource types follow Kubernetes conventions correctly with proper TypeMeta/ObjectMeta embedding, appropriate code-generation markers for client-gen and deepcopy-gen, and clear field documentation. The non-namespaced resource configuration is appropriate for node-local GPU resources.

client-go/nvgrpc/watcher.go (1)

15-170: LGTM! Solid watch implementation with proper lifecycle management.

The watcher correctly implements Kubernetes watch semantics with:

  • Idempotent shutdown via sync.Once
  • Proper context cancellation and cleanup
  • Correct gRPC status code mapping (lines 147-150 map codes to 410 Expired for informer re-list)
  • Structured logging at appropriate verbosity levels

The implementation follows the coding guidelines for context cancellation and shutdown handling.

api/device/v1alpha1/converter.go (1)

23-133: LGTM! Well-structured converter interface with proper code-generation annotations.

The Converter interface correctly uses SchemeGroupVersion.String() for APIVersion (lines 110, 118), ensuring the full "device.nvidia.com/v1alpha1" format. The goverter annotations properly map fields between protobuf and Kubernetes types, and timestamp conversion handles nil values safely.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (1)

1-87: LGTM! Clean client implementation following Kubernetes patterns.

The GPU client correctly implements Kubernetes client-go conventions with:

  • Proper context propagation and cancellation cleanup
  • Structured logging at appropriate verbosity levels (V(4-6))
  • Resource version handling for optimistic concurrency
  • Correct error handling with early cleanup in Watch method

The implementation uses client-go for Kubernetes API interactions as required by coding guidelines, and gpuStreamAdapter properly implements the nvgrpc.Source interface with Next() and Close() methods.

client-go/Makefile (1)

19-213: Well-structured client-go build system with proper code generation orchestration.

The Makefile correctly orchestrates client-gen, lister-gen, and informer-gen with proper tool versioning and overlay application. The version embedding via LDFLAGS enables runtime version reporting. The boilerplate file (hack/boilerplate.go.txt) contains a valid Apache 2.0 license header that will be applied to generated code.

api/Makefile (1)

19-206: Well-structured build workflow with comprehensive code generation.

The Makefile properly orchestrates protobuf generation, deepcopy generation, and conversion generation with per-version iteration. Tool versioning from .versions.yaml and the go-install-tool macro with GOTOOLCHAIN support ensure reproducible builds. The file has the required Apache 2.0 license header and follows project conventions.

Copy link
Contributor

@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

♻️ Duplicate comments (8)
client-go/version/version.go (1)

15-15: Add package-level godoc comment.

The coding guidelines require package-level godoc for all Go packages. Add a package comment describing the purpose of this package.

As per coding guidelines, package-level godoc is required for all Go packages.

🔎 Suggested addition
+// Package version provides build-time version information and user-agent
+// string generation for the nvidia-device-api-client.
 package version
client-go/Makefile (1)

187-187: Declare the tools target as PHONY.

The tools target should be declared .PHONY since it doesn't produce a file output and is used as a convenience alias for tool binaries.

🔎 Proposed fix
+.PHONY: tools
 tools: $(CLIENT_GEN) $(LISTER_GEN) $(INFORMER_GEN)
client-go/examples/controller-shim/main.go (1)

60-64: The informer factory is still never started (unresolved from previous review).

The comment on line 62 states "the Manager will start the injected informer," but this is incorrect. Controller-runtime only starts informers created through its own cache. The gRPC-backed factory must be started explicitly with factory.Start(stopCh), otherwise the cache never populates and reconciliation fails silently.

Suggested fix

Start the factory after creating the manager but before starting it:

 	if err != nil {
 		setupLog.Error(err, "unable to create manager")
 		os.Exit(1)
 	}

+	// Start the gRPC-backed informer factory. The manager does NOT automatically
+	// start externally created informers; they must be started explicitly.
+	ctx := ctrl.SetupSignalHandler()
+	go factory.Start(ctx.Done())
+
+	// Wait for the informer cache to sync before starting reconciliation.
+	synced := factory.WaitForCacheSync(ctx.Done())
+	for gvk, isSynced := range synced {
+		if !isSynced {
+			setupLog.Error(nil, "failed to sync cache for resource", "gvk", gvk)
+			os.Exit(1)
+		}
+	}
+
 	if err = (&GPUReconciler{

Then update line 116 to reuse the context:

-	ctx := ctrl.SetupSignalHandler()
-
 	setupLog.Info("starting manager")
 	if err := mgr.Start(ctx); err != nil {

Based on learnings, use meaningful variable names such as synced for cache sync checks.

client-go/hack/overlays/client/versioned/integration_test.go (1)

209-213: Avoid calling t.Errorf from a goroutine.

Calling t.Errorf (or any t method) from a goroutine is unsafe and can cause race conditions or panics if the test completes before the goroutine executes. Consider using an error channel to capture the error and check it in the main test goroutine, or simply ignore the error since c.Start blocks until context cancellation and WaitForCacheSync will catch initialization failures.

Based on learnings, proper shutdown handling with context cancellation should be implemented in Go code.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1)

37-44: Validate config in NewForConfigAndClient.

NewForConfigAndClient accepts a config but doesn't validate it, potentially allowing invalid configurations (e.g., empty target, invalid logger) to propagate silently. Consider validating the config before constructing the client.

🔎 Proposed validation addition
 func NewForConfigAndClient(c *nvgrpc.Config, conn grpc.ClientConnInterface) (*DeviceV1alpha1Client, error) {
+	if err := c.Validate(); err != nil {
+		return nil, err
+	}
 	return &DeviceV1alpha1Client{
 		conn:   conn,
 		logger: c.GetLogger().WithName("device.v1alpha1"),
 	}, nil
 }
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (2)

1-11: Add package-level godoc comment.

The coding guidelines require package-level documentation for all Go packages. Based on learnings, package-level godoc is required for all Go packages.

🔎 Suggested documentation
+// Package fake provides fake implementations of the device v1alpha1 client
+// for testing purposes. These fakes use an in-memory ObjectTracker instead
+// of actual gRPC connections.
 package fake

13-15: Add function comment for exported method.

The coding guidelines require function comments for all exported Go functions. Based on learnings, function comments are required for all exported Go functions.

🔎 Suggested documentation
+// GPUs returns a fake GPUInterface for testing GPU operations
+// without requiring an actual gRPC connection.
 func (c *FakeDeviceV1alpha1) GPUs() v1alpha1.GPUInterface {
 	return newFakeGPUs(c)
 }
client-go/examples/fake-server/main.go (1)

190-203: Populate ListMeta.ResourceVersion for List-then-Watch pattern.

The GpuList response doesn't include metadata.resource_version, which is needed for clients to establish a watch from a consistent point (List-then-Watch pattern). Consider tracking and populating a list-level resource version.

🔎 Suggested fix
 func (s *fakeServer) ListGpus(ctx context.Context, req *pb.ListGpusRequest) (*pb.ListGpusResponse, error) {
 	s.mu.RLock()
 	defer s.mu.RUnlock()

+	// Find the highest ResourceVersion among all GPUs for list consistency
+	maxRv := "1"
+	for _, gpu := range s.gpus {
+		if gpu.ResourceVersion > maxRv {
+			maxRv = gpu.ResourceVersion
+		}
+	}
+
 	gpuList := &pb.GpuList{
+		Metadata: &pb.ListMeta{
+			ResourceVersion: maxRv,
+		},
 		Items: make([]*pb.Gpu, 0, len(s.gpus)),
 	}

 	for _, gpu := range s.gpus {
 		gpuList.Items = append(gpuList.Items, devicev1alpha1.ToProto(&gpu))
 	}

 	return &pb.ListGpusResponse{GpuList: gpuList}, nil
 }
🧹 Nitpick comments (5)
client-go/nvgrpc/config_test.go (2)

20-120: Use testify assertions per coding guidelines.

The tests currently use basic if statements with t.Errorf for assertions. According to the coding guidelines, Go tests should use testify/assert and testify/require for assertions.

🔎 Refactor to use testify/assert

Import testify at the top of the file:

 import (
 	"testing"
+
+	"github.com/stretchr/testify/assert"
 )

Then refactor the assertions. For example, in TestConfig_Default_TargetPrecedence:

 		t.Run(tt.name, func(t *testing.T) {
 			t.Setenv(NvidiaDeviceAPITargetEnvVar, tt.envTarget)
 
 			cfg := &Config{Target: tt.argTarget}
 			cfg.Default()
 
-			if cfg.Target != tt.wantTarget {
-				t.Errorf("Target = %q, want %q", cfg.Target, tt.wantTarget)
-			}
+			assert.Equal(t, tt.wantTarget, cfg.Target)
 		})

Similarly for TestConfig_Default_UserAgent:

 	t.Run("Populates default UserAgent if empty", func(t *testing.T) {
 		cfg := &Config{}
 		cfg.Default()
 
-		if cfg.UserAgent == "" {
-			t.Error("UserAgent should have been populated with version-based default")
-		}
+		assert.NotEmpty(t, cfg.UserAgent, "UserAgent should have been populated with version-based default")
 	})
 
 	t.Run("Preserves custom UserAgent", func(t *testing.T) {
 		custom := "my-custom-agent/1.0"
 		cfg := &Config{UserAgent: custom}
 		cfg.Default()
 
-		if cfg.UserAgent != custom {
-			t.Errorf("UserAgent = %q, want %q", cfg.UserAgent, custom)
-		}
+		assert.Equal(t, custom, cfg.UserAgent)
 	})

And for TestConfig_Validate:

 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			err := tt.cfg.Validate()
-			if (err != nil) != tt.wantErr {
-				t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr)
-			}
+			if tt.wantErr {
+				assert.Error(t, err)
+			} else {
+				assert.NoError(t, err)
+			}
 		})
 	}

As per coding guidelines, use testify for assertions in Go tests.


62-69: Consider verifying the actual default UserAgent value.

The test checks that UserAgent is not empty after calling Default(), but doesn't verify it matches the expected default from version.UserAgent(). This would make the test more precise and catch regressions in the default value logic.

🔎 Suggested enhancement
+import (
+	"github.com/NVIDIA/nvidia-device-api-go/client-go/version"
+)
+
 	t.Run("Populates default UserAgent if empty", func(t *testing.T) {
 		cfg := &Config{}
 		cfg.Default()
 
-		if cfg.UserAgent == "" {
-			t.Error("UserAgent should have been populated with version-based default")
-		}
+		expected := version.UserAgent()
+		if cfg.UserAgent != expected {
+			t.Errorf("UserAgent = %q, want %q", cfg.UserAgent, expected)
+		}
 	})
client-go/DEVELOPMENT.md (1)

10-11: Optional: Minor style and formatting improvements.

Two minor style issues were detected:

  • Lines 10-11: Inconsistent list indentation (expected 2 spaces, actual 4).
  • Line 77: "inside of" can be simplified to "inside" for conciseness.
🔎 Proposed fixes

Fix list indentation:

 * **yq**: Required to parse version configuration.
-    * *macOS*: `brew install yq`
-    * *Linux*: See [yq installation](https://github.com/mikefarah/yq)
+  * *macOS*: `brew install yq`
+  * *Linux*: See [yq installation](https://github.com/mikefarah/yq)

Simplify phrasing:

-The directory structure inside of `hack/overlays/` **must exactly mirror** the structure of the generated code.
+The directory structure inside `hack/overlays/` **must exactly mirror** the structure of the generated code.

Also applies to: 77-77

api/Makefile (1)

36-36: Optional: Add space after # in comment.

Line 36 is missing a space after the # symbol, making it inconsistent with the other comments in the file.

🔎 Proposed fix
-#Helper for tools that need comma-separated package paths
+# Helper for tools that need comma-separated package paths
client-go/nvgrpc/watcher_test.go (1)

154-177: Avoid time.Sleep in tests for synchronization.

Line 160 uses time.Sleep(10 * time.Millisecond) to "allow the receive loop to start." This introduces flakiness and slows down tests. Consider using synchronization primitives (e.g., a channel signal from the watcher's receive loop) or relying on the existing timeout-based assertions.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1072d57 and 3891ded.

⛔ Files ignored due to path filters (28)
  • api/device/v1alpha1/zz_generated.conversion.go is excluded by !api/**/zz_generated.*
  • api/device/v1alpha1/zz_generated.deepcopy.go is excluded by !api/**/zz_generated.*
  • api/gen/go/device/v1alpha1/gpu.pb.go is excluded by !**/*.pb.go, !**/gen/**, !api/gen/**
  • api/go.sum is excluded by !**/*.sum
  • client-go/client/versioned/clientset.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/clientset_generated.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/register.go is excluded by !client-go/client/**
  • client-go/client/versioned/integration_test.go is excluded by !client-go/client/**
  • client-go/client/versioned/scheme/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/scheme/register.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/device_client.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_gpu.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/generated_expansion.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/gpu.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go is excluded by !client-go/client/**
  • client-go/go.sum is excluded by !**/*.sum
  • client-go/informers/externalversions/device/interface.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/device/v1alpha1/gpu.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/device/v1alpha1/interface.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/factory.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/generic.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go is excluded by !client-go/informers/**
  • client-go/listers/device/v1alpha1/expansion_generated.go is excluded by !client-go/listers/**
  • client-go/listers/device/v1alpha1/gpu.go is excluded by !client-go/listers/**
📒 Files selected for processing (47)
  • .coderabbit.yaml (1 hunks)
  • .gitignore (1 hunks)
  • .versions.yaml (1 hunks)
  • api/Makefile (5 hunks)
  • api/device/v1alpha1/converter.go (1 hunks)
  • api/device/v1alpha1/doc.go (1 hunks)
  • api/device/v1alpha1/gpu_conversion.go (1 hunks)
  • api/device/v1alpha1/gpu_conversion_test.go (1 hunks)
  • api/device/v1alpha1/gpu_types.go (1 hunks)
  • api/device/v1alpha1/register.go (1 hunks)
  • api/go.mod (2 hunks)
  • api/hack/boilerplate.go.txt (1 hunks)
  • api/proto/device/v1alpha1/gpu.proto (4 hunks)
  • client-go/DEVELOPMENT.md (1 hunks)
  • client-go/Makefile (1 hunks)
  • client-go/README.md (1 hunks)
  • client-go/examples/README.md (1 hunks)
  • client-go/examples/basic-client/README.md (1 hunks)
  • client-go/examples/basic-client/main.go (1 hunks)
  • client-go/examples/controller-shim/README.md (1 hunks)
  • client-go/examples/controller-shim/main.go (1 hunks)
  • client-go/examples/fake-server/README.md (1 hunks)
  • client-go/examples/fake-server/main.go (1 hunks)
  • client-go/examples/streaming-daemon/README.md (1 hunks)
  • client-go/examples/streaming-daemon/main.go (1 hunks)
  • client-go/go.mod (1 hunks)
  • client-go/hack/apply-overlays.sh (1 hunks)
  • client-go/hack/boilerplate.go.txt (1 hunks)
  • client-go/hack/boilerplate_overlay.go.txt (1 hunks)
  • client-go/hack/overlays/client/versioned/clientset.go (1 hunks)
  • client-go/hack/overlays/client/versioned/integration_test.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1 hunks)
  • client-go/nvgrpc/client_conn.go (1 hunks)
  • client-go/nvgrpc/client_conn_test.go (1 hunks)
  • client-go/nvgrpc/config.go (1 hunks)
  • client-go/nvgrpc/config_test.go (1 hunks)
  • client-go/nvgrpc/interceptors.go (1 hunks)
  • client-go/nvgrpc/interceptors_test.go (1 hunks)
  • client-go/nvgrpc/options.go (1 hunks)
  • client-go/nvgrpc/options_test.go (1 hunks)
  • client-go/nvgrpc/watcher.go (1 hunks)
  • client-go/nvgrpc/watcher_test.go (1 hunks)
  • client-go/version/version.go (1 hunks)
  • client-go/version/version_test.go (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • api/device/v1alpha1/gpu_conversion_test.go
  • client-go/examples/controller-shim/README.md
  • api/hack/boilerplate.go.txt
🚧 Files skipped from review as they are similar to previous changes (21)
  • client-go/examples/basic-client/README.md
  • client-go/version/version_test.go
  • client-go/nvgrpc/client_conn.go
  • client-go/go.mod
  • client-go/nvgrpc/interceptors_test.go
  • api/proto/device/v1alpha1/gpu.proto
  • .gitignore
  • client-go/nvgrpc/config.go
  • client-go/nvgrpc/options.go
  • api/device/v1alpha1/doc.go
  • api/go.mod
  • client-go/examples/README.md
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go
  • client-go/hack/boilerplate.go.txt
  • client-go/hack/boilerplate_overlay.go.txt
  • .versions.yaml
  • client-go/examples/streaming-daemon/README.md
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go
  • api/device/v1alpha1/register.go
  • client-go/hack/apply-overlays.sh
  • client-go/nvgrpc/client_conn_test.go
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.go: Follow standard Go conventions with gofmt and golint
Use structured logging via log/slog in Go code
Wrap errors with context using fmt.Errorf("context: %w", err) in Go code
Within retry.RetryOnConflict blocks, return errors without wrapping to preserve retry behavior
Use meaningful variable names such as synced over ok for cache sync checks
Use client-go for Kubernetes API interactions in Go code
Prefer informers over direct API calls for watching Kubernetes resources
Implement proper shutdown handling with context cancellation in Go code
Package-level godoc required for all Go packages
Function comments required for all exported Go functions
Use inline comments for complex logic only in Go code
TODO comments should reference issues in Go code
Extract informer event handler setup into helper methods
Use separate informers for different Kubernetes resource types

Files:

  • client-go/version/version.go
  • client-go/nvgrpc/options_test.go
  • api/device/v1alpha1/gpu_conversion.go
  • client-go/nvgrpc/config_test.go
  • client-go/examples/streaming-daemon/main.go
  • client-go/examples/fake-server/main.go
  • client-go/nvgrpc/interceptors.go
  • api/device/v1alpha1/gpu_types.go
  • client-go/hack/overlays/client/versioned/clientset.go
  • client-go/examples/controller-shim/main.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • api/device/v1alpha1/converter.go
  • client-go/nvgrpc/watcher.go
  • client-go/examples/basic-client/main.go
  • client-go/nvgrpc/watcher_test.go
**/*_test.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*_test.go: Use envtest for testing Kubernetes controllers instead of fake clients
Use testify/assert and testify/require for assertions in Go tests
Write table-driven tests when testing multiple scenarios in Go
Name Go tests descriptively using format: TestFunctionName_Scenario_ExpectedBehavior

Files:

  • client-go/nvgrpc/options_test.go
  • client-go/nvgrpc/config_test.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/nvgrpc/watcher_test.go
🧠 Learnings (12)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : TODO comments should reference issues in Go code

Applied to files:

  • client-go/version/version.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Package-level godoc required for all Go packages

Applied to files:

  • client-go/version/version.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Function comments required for all exported Go functions

Applied to files:

  • client-go/version/version.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Use `envtest` for testing Kubernetes controllers instead of fake clients

Applied to files:

  • client-go/examples/fake-server/main.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/hack/overlays/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code

Applied to files:

  • client-go/hack/overlays/client/versioned/clientset.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/examples/basic-client/main.go
  • client-go/README.md
  • client-go/DEVELOPMENT.md
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Prefer informers over direct API calls for watching Kubernetes resources

Applied to files:

  • client-go/examples/controller-shim/main.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/nvgrpc/watcher.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use separate informers for different Kubernetes resource types

Applied to files:

  • client-go/examples/controller-shim/main.go
  • client-go/hack/overlays/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use meaningful variable names such as `synced` over `ok` for cache sync checks

Applied to files:

  • client-go/examples/controller-shim/main.go
  • client-go/hack/overlays/client/versioned/integration_test.go
📚 Learning: 2025-11-04T06:31:02.147Z
Learnt from: Gyan172004
Repo: NVIDIA/NVSentinel PR: 223
File: platform-connectors/pkg/nodemetadata/processor.go:0-0
Timestamp: 2025-11-04T06:31:02.147Z
Learning: In platform-connectors/pkg/nodemetadata/processor.go, the NewProcessor function does not perform a nil check on the config parameter because the caller is expected to guarantee a non-nil config is provided.

Applied to files:

  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Implement proper shutdown handling with context cancellation in Go code

Applied to files:

  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/nvgrpc/watcher.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Keep Go dependencies minimal and up-to-date

Applied to files:

  • api/Makefile
🧬 Code graph analysis (10)
client-go/nvgrpc/options_test.go (1)
client-go/nvgrpc/options.go (4)
  • DialOption (23-23)
  • WithLogger (32-36)
  • WithUnaryInterceptor (39-43)
  • WithStreamInterceptor (46-50)
api/device/v1alpha1/gpu_conversion.go (2)
api/device/v1alpha1/converter.go (1)
  • Converter (30-104)
api/device/v1alpha1/gpu_types.go (2)
  • GPU (55-61)
  • GPUList (67-71)
client-go/nvgrpc/config_test.go (2)
client-go/nvgrpc/config.go (3)
  • DefaultNvidiaDeviceAPISocket (31-31)
  • NvidiaDeviceAPITargetEnvVar (28-28)
  • Config (41-49)
client-go/version/version.go (1)
  • UserAgent (28-35)
client-go/examples/fake-server/main.go (3)
client-go/nvgrpc/config.go (2)
  • NvidiaDeviceAPITargetEnvVar (28-28)
  • DefaultNvidiaDeviceAPISocket (31-31)
api/device/v1alpha1/gpu_types.go (3)
  • GPU (55-61)
  • GPUSpec (24-30)
  • GPUStatus (35-45)
api/device/v1alpha1/gpu_conversion.go (1)
  • ToProto (35-40)
client-go/hack/overlays/client/versioned/clientset.go (3)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (6)
  • DeviceV1alpha1Interface (9-12)
  • DeviceV1alpha1Client (15-18)
  • NewForConfig (27-35)
  • NewForConfigAndClient (39-44)
  • NewForConfigOrDie (48-55)
  • New (58-63)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/nvgrpc/client_conn.go (1)
  • ClientConnFor (26-72)
client-go/examples/controller-shim/main.go (4)
client-go/hack/overlays/client/versioned/clientset.go (1)
  • New (79-83)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1)
  • New (58-63)
client-go/nvgrpc/config.go (3)
  • NvidiaDeviceAPITargetEnvVar (28-28)
  • DefaultNvidiaDeviceAPISocket (31-31)
  • Config (41-49)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (1)
  • GPUInterface (22-27)
api/device/v1alpha1/converter.go (2)
api/device/v1alpha1/gpu_types.go (4)
  • GPU (55-61)
  • GPUList (67-71)
  • GPUSpec (24-30)
  • GPUStatus (35-45)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
client-go/examples/basic-client/main.go (3)
client-go/hack/overlays/client/versioned/clientset.go (2)
  • New (79-83)
  • NewForConfig (32-44)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (2)
  • New (58-63)
  • NewForConfig (27-35)
client-go/nvgrpc/config.go (3)
  • NvidiaDeviceAPITargetEnvVar (28-28)
  • DefaultNvidiaDeviceAPISocket (31-31)
  • Config (41-49)
client-go/nvgrpc/watcher_test.go (1)
client-go/nvgrpc/watcher.go (1)
  • NewWatcher (49-64)
🪛 checkmake (0.2.2)
client-go/Makefile

[warning] 187-187: Target "tools" should be declared PHONY.

(phonydeclared)

🪛 LanguageTool
client-go/DEVELOPMENT.md

[style] ~77-~77: This phrase is redundant. Consider using “inside”.
Context: ... informers/) The directory structure inside of hack/overlays/ *must exactly mirror...

(OUTSIDE_OF)

🪛 markdownlint-cli2 (0.18.1)
client-go/DEVELOPMENT.md

10-10: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


11-11: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)

🔇 Additional comments (32)
client-go/nvgrpc/config_test.go (1)

1-120: Well-structured test file with comprehensive coverage.

The tests follow good practices:

  • Table-driven tests for scenarios with multiple inputs
  • Subtests using t.Run for logical grouping
  • Proper use of t.Setenv for environment variable testing
  • Clear test naming and scenarios

The test coverage for Config.Default() and Config.Validate() is comprehensive, covering target precedence, user agent defaulting, and validation scenarios.

.coderabbit.yaml (1)

19-24: LGTM! Well-organized ignore patterns for generated code.

The path_filters appropriately exclude generated artifacts (protobuf bindings, deepcopy/conversion helpers, clientset, listers, and informers) from auto-review, reducing noise while maintaining review coverage on handwritten code.

client-go/nvgrpc/options_test.go (1)

25-65: LGTM! Well-structured test for option composition.

The test correctly validates DialOption behavior, including logger assignment and multiple interceptor appends. The use of subtests keeps the assertions organized.

client-go/hack/overlays/client/versioned/integration_test.go (4)

33-72: LGTM! Clean test setup and Get subtest.

The bufconn-based in-process gRPC server setup is well-structured, and the Get subtest correctly validates basic retrieval functionality.


74-129: LGTM! Comprehensive List and Watch subtests.

Both subtests correctly validate their respective operations, including initial snapshots and live event handling in the Watch flow.


131-182: LGTM! Proper informer lifecycle and sync validation.

The subtest correctly instantiates the informer before starting the factory, waits for cache sync, and uses polling to verify cache updates. This aligns with Kubernetes informer best practices.


254-336: LGTM! Well-implemented thread-safe mock server.

The mock GPU server correctly implements concurrent access protection with RWMutex, handles initial snapshots, and properly manages context cancellation in the watch loop.

client-go/nvgrpc/interceptors.go (2)

27-59: LGTM! Well-structured unary interceptor.

The latency interceptor correctly measures RPC duration, handles errors with appropriate logging levels (V(4) for cancellation, Error for failures, V(6) for success), and returns the original error without modification.


61-92: LGTM! Well-structured stream interceptor.

The stream latency interceptor correctly measures stream establishment duration and uses appropriate logging levels (V(4) for cancellation and successful establishment, Error for failures).

api/device/v1alpha1/gpu_types.go (1)

21-71: LGTM! Well-defined Kubernetes CRD types.

The GPU resource types follow Kubernetes API conventions with appropriate code generation markers (+genclient, +k8s:deepcopy-gen) and clear documentation. The non-namespaced, read-only design (onlyVerbs=get,list,watch) is appropriate for node-local device resources.

api/device/v1alpha1/gpu_conversion.go (1)

21-56: LGTM! Nil-safe conversion helpers with appropriate build tags.

The conversion helpers correctly implement nil-safety and delegate to the generated ConverterImpl. The !goverter build tag appropriately excludes this file from goverter's code generation phase to avoid circular dependencies.

client-go/nvgrpc/watcher.go (4)

32-46: LGTM! Well-designed Source interface and Watcher type.

The Source interface provides a clean abstraction for event streams, and the Watcher type correctly uses sync.Once to ensure idempotent shutdown, addressing previous race condition concerns.

Based on learnings, proper shutdown handling with context cancellation is implemented in Go code.


48-76: LGTM! Proper initialization and idempotent shutdown.

The NewWatcher constructor correctly initializes all fields and starts the receive loop. The Stop method is now idempotent using sync.Once, which properly resolves the previous race condition concern with double-close protection.

Based on learnings, proper shutdown handling with context cancellation is implemented in Go code.


83-136: LGTM! Robust receive loop with proper error handling.

The receive loop correctly handles normal termination (EOF, Canceled), maps event types, and uses select to prevent sending to a closed channel. The defer ordering ensures proper cleanup sequence.

Based on learnings, proper shutdown handling with context cancellation is implemented in Go code.


138-170: LGTM! Correct gRPC-to-Kubernetes error translation.

The sendError helper appropriately maps gRPC status codes to Kubernetes status codes, with the critical 410 Expired mapping for OutOfRange/ResourceExhausted/InvalidArgument that triggers informer re-list behavior.

client-go/examples/basic-client/main.go (1)

30-83: LGTM! Clean example demonstrating client usage.

The example correctly demonstrates List, Get, and status inspection operations using the versioned clientset. The use of nvgrpc.NvidiaDeviceAPITargetEnvVar and nvgrpc.DefaultNvidiaDeviceAPISocket constants (lines 36-38) ensures consistency with library defaults.

Based on learnings, client-go is used for Kubernetes API interactions in Go code.

client-go/nvgrpc/watcher_test.go (1)

179-239: LGTM!

The test utilities (FakeObject and FakeSource) are well-designed. The FakeSource.Close() method properly handles idempotent closure with a select statement to avoid double-close panics, and the Next() method correctly prioritizes error injection before events for deterministic test behavior.

api/device/v1alpha1/converter.go (2)

23-104: LGTM!

The Converter interface is well-structured with appropriate goverter directives for code generation. The field mappings (e.g., UuidUUID, MetadataObjectMeta/ListMeta) align with protobuf and Kubernetes naming conventions, and the goverter:ignore directives properly exclude protobuf internal fields and Kubernetes-specific metadata fields.


122-133: LGTM!

The timestamp conversion helpers correctly handle nil protobuf timestamps by returning zero-valued metav1.Time, and the ToProtobufTimestamp conversion properly wraps the Go time in a protobuf timestamp.

client-go/examples/fake-server/README.md (1)

1-29: LGTM!

The documentation is clear and comprehensive. It properly explains the sudo requirement for the default socket path, provides instructions for running without root using NVIDIA_DEVICE_API_TARGET, and describes the simulated behavior (8 GPUs with 2-second status toggles).

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1)

17-24: LGTM!

The ClientConn() method correctly returns a typed nil for the fake implementation, which is appropriate for testing scenarios where no actual gRPC connection is needed.

client-go/examples/streaming-daemon/main.go (2)

37-77: LGTM!

The initialization logic correctly uses nvgrpc.DefaultNvidiaDeviceAPISocket as the default target, properly wires custom interceptors for tracing and watch monitoring, and establishes the gRPC connection with appropriate error handling and deferred cleanup.


99-146: LGTM!

The watch stream handling is robust: it properly handles watch errors by checking for watch.Error events and extracting metav1.Status, performs type assertions on GPU objects, extracts readiness from conditions using meta.IsStatusConditionTrue, and gracefully shuts down on context cancellation.

client-go/hack/overlays/client/versioned/clientset.go (2)

12-24: LGTM!

The Interface and Clientset structure follows standard Kubernetes client-go patterns, and the DeviceV1alpha1() accessor properly exposes the typed client interface.


26-65: LGTM!

The constructor pattern is well-designed: NewForConfig handles connection creation and delegates to NewForConfigAndClient, both constructors properly validate nil parameters, and the shallow copy pattern prevents config mutation. The separation allows users to customize the connection (e.g., with interceptors) when needed.

client-go/examples/fake-server/main.go (4)

42-91: LGTM!

The main function properly handles socket path resolution using nvgrpc.NvidiaDeviceAPITargetEnvVar and nvgrpc.DefaultNvidiaDeviceAPISocket, creates the socket directory with appropriate permissions, removes stale sockets, and implements graceful shutdown with signal handling and socket cleanup.


100-164: LGTM!

The fake server initialization and simulation logic correctly create 8 GPUs with initial ResourceVersion: "1", and the simulateChanges goroutine properly increments ResourceVersion on each update (supporting Kubernetes watch semantics), toggles the Ready condition, updates LastTransitionTime, and broadcasts changes to registered watch streams.


177-188: LGTM!

The GetGpu implementation correctly searches the in-memory GPU slice and returns a proper codes.NotFound gRPC error when the GPU is not found.


205-255: LGTM!

The WatchGpus implementation correctly sends initial ADDED events for all GPUs, registers for ongoing updates, streams MODIFIED events to the client, and properly cleans up the listener registration on stream termination or context cancellation.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (3)

9-22: LGTM!

The DeviceV1alpha1Interface properly exposes both the ClientConn() accessor and the GPUsGetter interface, and the DeviceV1alpha1Client struct correctly maintains the gRPC connection and logger fields. The GPUs() method appropriately delegates to newGPUs.


24-35: LGTM!

The NewForConfig constructor correctly shallow-copies the config to prevent mutation, creates the gRPC connection via nvgrpc.ClientConnFor, and delegates to NewForConfigAndClient with proper error propagation.


65-73: LGTM!

The ClientConn() method properly handles nil receivers and returns the underlying gRPC connection interface, following defensive coding practices.

@pteranodan pteranodan force-pushed the add-go-sdk branch 2 times, most recently from 3806f19 to 4f3e806 Compare December 20, 2025 17:05
@pteranodan
Copy link
Contributor Author

pteranodan commented Dec 20, 2025

@coderabbitai full review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 20, 2025

✅ Actions performed

Full review triggered.

Copy link
Contributor

@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: 12

♻️ Duplicate comments (7)
client-go/hack/overlays/client/versioned/integration_test.go (1)

209-213: Avoid calling t.Errorf from a goroutine.

Calling t.Errorf from a goroutine is unsafe and can cause race conditions if the test completes before the goroutine executes. Use an error channel to safely propagate errors to the main test goroutine.

🔎 Suggested fix using an error channel
+		errCh := make(chan error, 1)
 		go func() {
 			if err := c.Start(ctx); err != nil {
-				t.Errorf("Cache failed to start: %v", err)
+				errCh <- err
 			}
+			close(errCh)
 		}()

+		// Check for startup errors after sync
+		if !c.WaitForCacheSync(ctx) {
+			t.Fatal("Controller-runtime cache failed to sync")
+		}
+
+		select {
+		case err := <-errCh:
+			if err != nil {
+				t.Fatalf("Cache failed to start: %v", err)
+			}
+		default:
+		}
-
-		if !c.WaitForCacheSync(ctx) {
-			t.Fatal("Controller-runtime cache failed to sync")
-		}
client-go/examples/controller-shim/main.go (3)

15-15: Add package-level documentation.

As per coding guidelines, package-level godoc is required. This example demonstrates an important integration pattern.

Suggested addition
+// Package main demonstrates a controller-shim pattern that uses a gRPC-backed
+// informer with controller-runtime to reconcile GPU resources over a Unix domain socket.
+// This example shows how to inject a custom informer into the manager's cache to enable
+// Kubernetes-style reconciliation loops without requiring a real API server.
 package main

130-147: Add godoc comments for exported methods.

The exported methods Reconcile and SetupWithManager lack documentation. Coding guidelines require function comments for all exported Go functions.

Suggested additions
+// Reconcile retrieves the requested GPU resource from the gRPC-backed cache
+// and logs its name and UUID. It returns without error if the GPU is not found.
 func (r *GPUReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
 	log := ctrl.LoggerFrom(ctx)

 	var gpu devicev1alpha1.GPU
 	// The Get call is transparently routed through the injected gRPC-backed informer.
 	if err := r.Get(ctx, req.NamespacedName, &gpu); err != nil {
 		return ctrl.Result{}, client.IgnoreNotFound(err)
 	}

 	log.Info("Reconciled GPU", "name", gpu.Name, "uuid", gpu.Spec.UUID)
 	return ctrl.Result{}, nil
 }

+// SetupWithManager registers this reconciler with the provided manager,
+// configuring it to watch GPU resources.
 func (r *GPUReconciler) SetupWithManager(mgr ctrl.Manager) error {

60-64: The informer factory is never started.

The comment on line 62 states the Manager will start the injected informer, but controller-runtime only starts informers created through its own cache machinery. The gRPC-backed informer from factory needs to be started explicitly; otherwise, the cache will never populate and reconciliation won't occur.

Suggested fix
 	factory := informers.NewSharedInformerFactory(clientset, 10*time.Minute)
 	gpuInformer := factory.Device().V1alpha1().GPUs().Informer()

+	// Start the factory in the background. The informer must be running
+	// before the manager attempts to use the cache.
+	stopCh := make(chan struct{})
+	go func() {
+		<-ctrl.SetupSignalHandler().Done()
+		close(stopCh)
+	}()
+	factory.Start(stopCh)
+
+	// Wait for the cache to sync before proceeding.
+	if !toolscache.WaitForCacheSync(stopCh, gpuInformer.HasSynced) {
+		setupLog.Error(nil, "failed to sync informer cache")
+		os.Exit(1)
+	}
api/proto/device/v1alpha1/gpu.proto (1)

35-37: Inconsistent indentation in comment blocks.

Lines 35-37 use tabs while surrounding lines use spaces. This was flagged in a previous review but appears unaddressed.

Suggested fix
   // resource_version represents the internal version of this object.
   //
   // Value must be treated as opaque by clients and passed unmodified back to the server.
-	// Populated by the system.
-	// Read-only.
-	// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
+  // Populated by the system.
+  // Read-only.
+  // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
   string resource_version = 2;
client-go/examples/fake-server/main.go (1)

190-203: ListMeta is not populated in the response.

The GpuList response doesn't include metadata.resource_version, which is needed for clients to establish a watch from a consistent point (List-then-Watch pattern). This was raised in a previous review but doesn't appear to be addressed yet.

🔎 Suggested fix
 func (s *fakeServer) ListGpus(ctx context.Context, req *pb.ListGpusRequest) (*pb.ListGpusResponse, error) {
 	s.mu.RLock()
 	defer s.mu.RUnlock()

+	// Compute highest resource version for list metadata
+	var maxRv int
+	for _, gpu := range s.gpus {
+		if rv, _ := strconv.Atoi(gpu.ResourceVersion); rv > maxRv {
+			maxRv = rv
+		}
+	}
+
 	gpuList := &pb.GpuList{
+		Metadata: &pb.ListMeta{
+			ResourceVersion: strconv.Itoa(maxRv),
+		},
 		Items: make([]*pb.Gpu, 0, len(s.gpus)),
 	}
client-go/Makefile (1)

187-187: Declare tools target as .PHONY.

This issue was previously flagged. The tools target should be declared .PHONY since it doesn't produce a file named "tools".

🧹 Nitpick comments (9)
client-go/nvgrpc/interceptors_test.go (3)

17-27: Add testify imports per coding guidelines.

The coding guidelines specify using testify/assert and testify/require for assertions in Go tests, but these packages are not imported. The current tests use t.Fatalf for assertions (lines 62, 99).

As per coding guidelines, please add the testify imports and refactor assertions accordingly.

🔎 Proposed fix
 import (
 	"context"
 	"errors"
 	"testing"
 	"time"
 
 	logr "github.com/go-logr/logr/testing"
+	"github.com/stretchr/testify/assert"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 )

Then replace t.Fatalf calls with assert.ErrorIs:

-			if !errors.Is(err, tt.invokerErr) {
-				t.Fatalf("Returned error mismatch. Got %v, want %v", err, tt.invokerErr)
-			}
+			assert.ErrorIs(t, err, tt.invokerErr, "Returned error mismatch")

29-66: Remove unused expectedCode field.

The expectedCode field is defined in the test table (line 35) and populated for each test case, but it's never used in the test execution. This is dead code that should be removed to improve clarity.

Additionally, the sleep logic on lines 54-56 when !tt.log is unclear—it appears to simulate latency when logging is disabled, but the test doesn't verify any timing behavior or performance characteristics.

🔎 Proposed cleanup
 	tests := []struct {
 		name         string
 		method       string
 		log          bool
 		invokerErr   error
-		expectedCode codes.Code
 	}{
-		{"Returns OK code for successful call", "/svc/success", true, nil, codes.OK},
-		{"Returns internal status error on internal error", "/svc/internal_error", true, status.Error(codes.Internal, "fail"), codes.Internal},
-		{"Returns canceled status error when canceled", "/svc/cancel", true, status.Error(codes.Canceled, ""), codes.Canceled},
-		{"Returns deadline exceeded status error on timeout", "/svc/timeout", true, status.Error(codes.DeadlineExceeded, ""), codes.DeadlineExceeded},
-		{"Does not log if level too low", "/svc/skip_log", false, nil, codes.OK},
+		{"Returns OK code for successful call", "/svc/success", true, nil},
+		{"Returns internal status error on internal error", "/svc/internal_error", true, status.Error(codes.Internal, "fail")},
+		{"Returns canceled status error when canceled", "/svc/cancel", true, status.Error(codes.Canceled, "")},
+		{"Returns deadline exceeded status error on timeout", "/svc/timeout", true, status.Error(codes.DeadlineExceeded, "")},
+		{"Does not log if level too low", "/svc/skip_log", false, nil},
 	}

If the sleep is intended to verify the interceptor doesn't add overhead when logging is disabled, consider adding a comment explaining this intent or removing it if not testing performance.


68-103: Clarify the purpose of sleep in non-logging test cases.

Similar to the unary interceptor test, the sleep on lines 91-93 when !tt.log is executed but its purpose is unclear. If this is intended to verify that the interceptor doesn't add significant overhead when logging is disabled, consider adding a comment to document this intent. Otherwise, if it's not testing performance characteristics, the sleep could be removed.

💡 Example clarifying comment
 			streamer := func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, opts ...grpc.CallOption) (grpc.ClientStream, error) {
 				if !tt.log {
+					// Simulate minimal latency to verify interceptor overhead is negligible when logging disabled
 					time.Sleep(1 * time.Millisecond)
 				}
 				return nil, tt.streamerErr
 			}
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1)

14-23: Consider adding context to stream errors.

When Recv() fails, the error is returned without additional context. Adding context would improve debuggability when stream errors occur.

As per coding guidelines, wrap errors with context in Go code.

🔎 Proposed enhancement
 func (a *gpuStreamAdapter) Next() (string, runtime.Object, error) {
 	resp, err := a.stream.Recv()
 	if err != nil {
-		return "", nil, err
+		return "", nil, fmt.Errorf("failed to receive from GPU watch stream: %w", err)
 	}

 	obj := devicev1alpha1.FromProto(resp.GetObject())

 	return resp.GetType(), obj, nil
 }

Note: You'll need to import fmt at the top of the file.

client-go/DEVELOPMENT.md (2)

77-77: Minor style improvement: simplify "inside of" to "inside".

The phrase "inside of" is redundant and can be simplified to "inside" for clearer writing.

🔎 Suggested fix
-The directory structure inside of `hack/overlays/` **must exactly mirror** the structure of the generated code.
+The directory structure inside `hack/overlays/` **must exactly mirror** the structure of the generated code.

10-11: Fix list indentation for markdown consistency.

The nested list items use 4-space indentation instead of the expected 2 spaces, which may cause formatting issues in some markdown renderers.

🔎 Suggested fix
 * **yq**: Required to parse version configuration.
-    * *macOS*: `brew install yq`
-    * *Linux*: See [yq installation](https://github.com/mikefarah/yq)
+  * *macOS*: `brew install yq`
+  * *Linux*: See [yq installation](https://github.com/mikefarah/yq)
client-go/examples/basic-client/main.go (1)

15-15: Add package-level documentation.

As per coding guidelines, package-level godoc is required for all Go packages. This example demonstrates the basic client usage pattern and should be documented.

Suggested addition
+// Package main demonstrates basic usage of the NVIDIA Device API client.
+// It shows how to list GPUs, fetch individual GPU details, and inspect
+// status conditions using the gRPC-backed versioned clientset.
 package main
client-go/nvgrpc/watcher_test.go (1)

154-177: Consider avoiding time.Sleep for test synchronization.

The time.Sleep(10 * time.Millisecond) on line 160 is a fragile synchronization mechanism that could cause flaky tests on slower CI runners.

🔎 Suggested improvement using channel synchronization

Consider adding a "ready" signal from the watcher's receive loop, or use a retry/poll pattern with shorter intervals:

// Alternative: poll until watcher is responsive
deadline := time.Now().Add(100 * time.Millisecond)
for time.Now().Before(deadline) {
    // The receive loop is running if we can read from done without blocking
    select {
    case <-time.After(time.Millisecond):
    default:
    }
}

Or expose a ready channel from the Watcher for tests to synchronize on.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (1)

43-56: Consider wrapping errors and documenting unused opts parameter.

Two observations:

  1. The opts metav1.GetOptions parameter is unused. If this is intentional (gRPC doesn't support these options), consider adding a brief comment or using _ metav1.GetOptions to make this explicit.
  2. Per coding guidelines, errors should be wrapped with context using fmt.Errorf("context: %w", err). However, if preserving the original gRPC error type for status extraction is intentional, this is acceptable.
🔎 Optional: Add error context
 func (c *gpus) Get(ctx context.Context, name string, opts metav1.GetOptions) (*devicev1alpha1.GPU, error) {
 	resp, err := c.client.GetGpu(ctx, &pb.GetGpuRequest{Name: name})
 	if err != nil {
-		return nil, err
+		return nil, fmt.Errorf("get GPU %q: %w", name, err)
 	}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3891ded and 3806f19.

⛔ Files ignored due to path filters (28)
  • api/device/v1alpha1/zz_generated.conversion.go is excluded by !api/**/zz_generated.*
  • api/device/v1alpha1/zz_generated.deepcopy.go is excluded by !api/**/zz_generated.*
  • api/gen/go/device/v1alpha1/gpu.pb.go is excluded by !**/*.pb.go, !**/gen/**, !api/gen/**
  • api/go.sum is excluded by !**/*.sum
  • client-go/client/versioned/clientset.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/clientset_generated.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/register.go is excluded by !client-go/client/**
  • client-go/client/versioned/integration_test.go is excluded by !client-go/client/**
  • client-go/client/versioned/scheme/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/scheme/register.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/device_client.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_gpu.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/generated_expansion.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/gpu.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go is excluded by !client-go/client/**
  • client-go/go.sum is excluded by !**/*.sum
  • client-go/informers/externalversions/device/interface.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/device/v1alpha1/gpu.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/device/v1alpha1/interface.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/factory.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/generic.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go is excluded by !client-go/informers/**
  • client-go/listers/device/v1alpha1/expansion_generated.go is excluded by !client-go/listers/**
  • client-go/listers/device/v1alpha1/gpu.go is excluded by !client-go/listers/**
📒 Files selected for processing (48)
  • .coderabbit.yaml (1 hunks)
  • .gitignore (1 hunks)
  • .versions.yaml (1 hunks)
  • Makefile (1 hunks)
  • api/Makefile (5 hunks)
  • api/device/v1alpha1/converter.go (1 hunks)
  • api/device/v1alpha1/doc.go (1 hunks)
  • api/device/v1alpha1/gpu_conversion.go (1 hunks)
  • api/device/v1alpha1/gpu_conversion_test.go (1 hunks)
  • api/device/v1alpha1/gpu_types.go (1 hunks)
  • api/device/v1alpha1/register.go (1 hunks)
  • api/go.mod (2 hunks)
  • api/hack/boilerplate.go.txt (1 hunks)
  • api/proto/device/v1alpha1/gpu.proto (4 hunks)
  • client-go/DEVELOPMENT.md (1 hunks)
  • client-go/Makefile (1 hunks)
  • client-go/README.md (1 hunks)
  • client-go/examples/README.md (1 hunks)
  • client-go/examples/basic-client/README.md (1 hunks)
  • client-go/examples/basic-client/main.go (1 hunks)
  • client-go/examples/controller-shim/README.md (1 hunks)
  • client-go/examples/controller-shim/main.go (1 hunks)
  • client-go/examples/fake-server/README.md (1 hunks)
  • client-go/examples/fake-server/main.go (1 hunks)
  • client-go/examples/streaming-daemon/README.md (1 hunks)
  • client-go/examples/streaming-daemon/main.go (1 hunks)
  • client-go/go.mod (1 hunks)
  • client-go/hack/apply-overlays.sh (1 hunks)
  • client-go/hack/boilerplate.go.txt (1 hunks)
  • client-go/hack/boilerplate_overlay.go.txt (1 hunks)
  • client-go/hack/overlays/client/versioned/clientset.go (1 hunks)
  • client-go/hack/overlays/client/versioned/integration_test.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1 hunks)
  • client-go/nvgrpc/client_conn.go (1 hunks)
  • client-go/nvgrpc/client_conn_test.go (1 hunks)
  • client-go/nvgrpc/config.go (1 hunks)
  • client-go/nvgrpc/config_test.go (1 hunks)
  • client-go/nvgrpc/interceptors.go (1 hunks)
  • client-go/nvgrpc/interceptors_test.go (1 hunks)
  • client-go/nvgrpc/options.go (1 hunks)
  • client-go/nvgrpc/options_test.go (1 hunks)
  • client-go/nvgrpc/watcher.go (1 hunks)
  • client-go/nvgrpc/watcher_test.go (1 hunks)
  • client-go/version/version.go (1 hunks)
  • client-go/version/version_test.go (1 hunks)
✅ Files skipped from review due to trivial changes (5)
  • api/hack/boilerplate.go.txt
  • client-go/hack/boilerplate.go.txt
  • client-go/examples/controller-shim/README.md
  • client-go/hack/boilerplate_overlay.go.txt
  • client-go/examples/fake-server/README.md
🚧 Files skipped from review as they are similar to previous changes (17)
  • client-go/version/version_test.go
  • client-go/examples/streaming-daemon/README.md
  • client-go/nvgrpc/client_conn.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • .gitignore
  • api/device/v1alpha1/gpu_conversion.go
  • client-go/nvgrpc/options.go
  • client-go/version/version.go
  • client-go/nvgrpc/interceptors.go
  • api/device/v1alpha1/converter.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/README.md
  • client-go/nvgrpc/options_test.go
  • client-go/nvgrpc/client_conn_test.go
  • client-go/nvgrpc/config.go
  • client-go/hack/apply-overlays.sh
  • api/device/v1alpha1/register.go
🧰 Additional context used
📓 Path-based instructions (3)
**/go.mod

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use go.mod for each service as a separate Go module with semantic import versioning

Files:

  • client-go/go.mod
  • api/go.mod
**/*.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.go: Follow standard Go conventions with gofmt and golint
Use structured logging via log/slog in Go code
Wrap errors with context using fmt.Errorf("context: %w", err) in Go code
Within retry.RetryOnConflict blocks, return errors without wrapping to preserve retry behavior
Use meaningful variable names such as synced over ok for cache sync checks
Use client-go for Kubernetes API interactions in Go code
Prefer informers over direct API calls for watching Kubernetes resources
Implement proper shutdown handling with context cancellation in Go code
Package-level godoc required for all Go packages
Function comments required for all exported Go functions
Use inline comments for complex logic only in Go code
TODO comments should reference issues in Go code
Extract informer event handler setup into helper methods
Use separate informers for different Kubernetes resource types

Files:

  • api/device/v1alpha1/gpu_conversion_test.go
  • api/device/v1alpha1/doc.go
  • client-go/nvgrpc/config_test.go
  • client-go/examples/streaming-daemon/main.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go
  • api/device/v1alpha1/gpu_types.go
  • client-go/nvgrpc/watcher.go
  • client-go/hack/overlays/client/versioned/clientset.go
  • client-go/examples/basic-client/main.go
  • client-go/examples/controller-shim/main.go
  • client-go/nvgrpc/watcher_test.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go
  • client-go/examples/fake-server/main.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/nvgrpc/interceptors_test.go
**/*_test.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*_test.go: Use envtest for testing Kubernetes controllers instead of fake clients
Use testify/assert and testify/require for assertions in Go tests
Write table-driven tests when testing multiple scenarios in Go
Name Go tests descriptively using format: TestFunctionName_Scenario_ExpectedBehavior

Files:

  • api/device/v1alpha1/gpu_conversion_test.go
  • client-go/nvgrpc/config_test.go
  • client-go/nvgrpc/watcher_test.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/nvgrpc/interceptors_test.go
🧠 Learnings (17)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/go.mod : Use `go.mod` for each service as a separate Go module with semantic import versioning

Applied to files:

  • client-go/go.mod
  • Makefile
  • api/go.mod
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code

Applied to files:

  • client-go/go.mod
  • client-go/examples/README.md
  • api/Makefile
  • client-go/hack/overlays/client/versioned/clientset.go
  • client-go/examples/basic-client/main.go
  • client-go/examples/basic-client/README.md
  • .versions.yaml
  • client-go/DEVELOPMENT.md
  • api/go.mod
  • client-go/Makefile
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Keep Go dependencies minimal and up-to-date

Applied to files:

  • client-go/go.mod
  • Makefile
  • api/Makefile
  • .versions.yaml
  • api/go.mod
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : TODO comments should reference issues in Go code

Applied to files:

  • client-go/go.mod
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Prefer informers over direct API calls for watching Kubernetes resources

Applied to files:

  • client-go/go.mod
  • client-go/nvgrpc/watcher.go
  • client-go/examples/controller-shim/main.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • api/go.mod
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Use `envtest` for testing Kubernetes controllers instead of fake clients

Applied to files:

  • client-go/go.mod
  • client-go/examples/README.md
  • client-go/nvgrpc/watcher_test.go
  • client-go/examples/fake-server/main.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • .versions.yaml
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: All files must include Apache 2.0 license header

Applied to files:

  • Makefile
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Follow standard Go conventions with gofmt and golint

Applied to files:

  • Makefile
  • .versions.yaml
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use meaningful variable names such as `synced` over `ok` for cache sync checks

Applied to files:

  • Makefile
  • client-go/examples/controller-shim/main.go
  • client-go/hack/overlays/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Implement proper shutdown handling with context cancellation in Go code

Applied to files:

  • client-go/nvgrpc/watcher.go
  • client-go/hack/overlays/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use separate informers for different Kubernetes resource types

Applied to files:

  • client-go/examples/controller-shim/main.go
  • client-go/hack/overlays/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Package-level godoc required for all Go packages

Applied to files:

  • client-go/examples/controller-shim/main.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Function comments required for all exported Go functions

Applied to files:

  • client-go/examples/controller-shim/main.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to data-models/protobufs/**/*.proto : Include comprehensive comments for all fields in Protocol Buffer messages

Applied to files:

  • api/proto/device/v1alpha1/gpu.proto
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to data-models/protobufs/**/*.proto : Use semantic versioning for breaking changes in Protocol Buffer messages

Applied to files:

  • api/proto/device/v1alpha1/gpu.proto
📚 Learning: 2025-12-01T17:53:20.067Z
Learnt from: jtschelling
Repo: NVIDIA/NVSentinel PR: 455
File: docs/designs/013-remediation-plugins.md:162-204
Timestamp: 2025-12-01T17:53:20.067Z
Learning: Code examples in design documents (docs/designs/) in the NVSentinel repository are illustrative stubs meant to show intent and architectural concepts, and do not need to be 100% correct or complete implementations (e.g., undefined variables, missing error handling, incomplete struct initialization are acceptable).

Applied to files:

  • api/go.mod
🧬 Code graph analysis (9)
api/device/v1alpha1/gpu_conversion_test.go (1)
api/device/v1alpha1/gpu_conversion.go (4)
  • FromProto (25-32)
  • ToProto (35-40)
  • FromProtoList (43-48)
  • ToProtoList (51-56)
client-go/examples/streaming-daemon/main.go (6)
client-go/hack/overlays/client/versioned/clientset.go (2)
  • New (79-83)
  • NewForConfigAndClient (48-65)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (2)
  • New (58-63)
  • NewForConfigAndClient (39-44)
client-go/nvgrpc/config.go (3)
  • NvidiaDeviceAPITargetEnvVar (28-28)
  • DefaultNvidiaDeviceAPISocket (31-31)
  • Config (41-49)
client-go/nvgrpc/options.go (4)
  • DialOption (23-23)
  • WithLogger (32-36)
  • WithUnaryInterceptor (39-43)
  • WithStreamInterceptor (46-50)
client-go/nvgrpc/client_conn.go (1)
  • ClientConnFor (26-72)
api/device/v1alpha1/gpu_types.go (1)
  • GPU (55-61)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1)
api/device/v1alpha1/gpu_conversion.go (1)
  • FromProto (25-32)
client-go/hack/overlays/client/versioned/clientset.go (3)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (6)
  • DeviceV1alpha1Interface (9-12)
  • DeviceV1alpha1Client (15-18)
  • NewForConfig (27-35)
  • NewForConfigAndClient (39-44)
  • NewForConfigOrDie (48-55)
  • New (58-63)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/nvgrpc/client_conn.go (1)
  • ClientConnFor (26-72)
client-go/nvgrpc/watcher_test.go (1)
client-go/nvgrpc/watcher.go (1)
  • NewWatcher (49-64)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (5)
api/device/v1alpha1/gpu_types.go (2)
  • GPU (55-61)
  • GPUList (67-71)
client-go/hack/overlays/client/versioned/clientset.go (1)
  • Interface (12-14)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1)
  • DeviceV1alpha1Client (15-18)
api/device/v1alpha1/gpu_conversion.go (1)
  • FromProto (25-32)
client-go/nvgrpc/watcher.go (1)
  • NewWatcher (49-64)
client-go/examples/fake-server/main.go (3)
client-go/nvgrpc/config.go (2)
  • NvidiaDeviceAPITargetEnvVar (28-28)
  • DefaultNvidiaDeviceAPISocket (31-31)
api/device/v1alpha1/gpu_types.go (3)
  • GPU (55-61)
  • GPUSpec (24-30)
  • GPUStatus (35-45)
api/device/v1alpha1/gpu_conversion.go (1)
  • ToProto (35-40)
client-go/hack/overlays/client/versioned/integration_test.go (5)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/hack/overlays/client/versioned/clientset.go (2)
  • NewForConfigAndClient (48-65)
  • New (79-83)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (2)
  • NewForConfigAndClient (39-44)
  • New (58-63)
api/device/v1alpha1/gpu_types.go (1)
  • GPU (55-61)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
client-go/nvgrpc/interceptors_test.go (1)
client-go/nvgrpc/interceptors.go (2)
  • NewLatencyUnaryInterceptor (28-59)
  • NewLatencyStreamInterceptor (62-92)
🪛 checkmake (0.2.2)
client-go/Makefile

[warning] 187-187: Target "tools" should be declared PHONY.

(phonydeclared)

🪛 LanguageTool
client-go/DEVELOPMENT.md

[style] ~77-~77: This phrase is redundant. Consider using “inside”.
Context: ... informers/) The directory structure inside of hack/overlays/ *must exactly mirror...

(OUTSIDE_OF)

🪛 markdownlint-cli2 (0.18.1)
client-go/DEVELOPMENT.md

10-10: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


11-11: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)

🔇 Additional comments (53)
client-go/examples/basic-client/README.md (1)

1-38: ✅ Documentation looks good.

The previous issue with the incorrect relative path (../../fake-server) has been resolved. Both references on lines 12 and 27 now correctly point to ../fake-server, which properly navigates from the basic-client directory to the fake-server example.

The README is well-structured with clear sections on key concepts, running instructions for both privileged and unprivileged execution, and concrete expected output examples. This provides developers with a solid reference implementation for the NVIDIA Device API Go Client.

client-go/examples/streaming-daemon/main.go (7)

42-48: LGTM!

The connection target resolution correctly uses the canonical constants from the nvgrpc package, addressing the previous review feedback.


50-61: LGTM!

The custom interceptor implementations correctly demonstrate metadata injection for unary calls and lifecycle logging for stream calls. The inline definitions are appropriate for example code.


63-77: LGTM!

The DialOptions configuration and gRPC connection setup correctly use the nvgrpc package patterns, with proper error handling and resource cleanup via defer.


79-85: LGTM!

The clientset initialization correctly uses NewForConfigAndClient which is appropriate when custom gRPC lifecycle or interceptor management is needed. The explanatory comment is helpful.


87-89: LGTM!

Proper shutdown handling implementation using signal.NotifyContext for graceful termination on SIGINT or SIGTERM, as required by coding guidelines.


91-97: LGTM!

The List call correctly demonstrates the unary interceptor trigger and handles errors appropriately for example code.


99-146: Watch implementation is correct, but consider the architectural pattern.

The Watch stream and event processing logic is well-implemented with proper error handling, type assertions, and cleanup. However, the coding guidelines prefer informers over direct API calls for watching Kubernetes resources.

While this example intentionally demonstrates manual Watch usage to showcase the stream interceptor behavior, consider documenting in comments or README that production code should typically use Informers for better reliability and caching benefits.

Based on coding guidelines: "Prefer informers over direct API calls for watching Kubernetes resources."

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1)

1-12: LGTM! Clean adapter structure.

The type definition is clear and appropriate for wrapping the gRPC stream into a Kubernetes-compatible event provider.

Makefile (1)

343-343: LGTM!

The addition of the hack/ ignore pattern aligns well with the overlay-based code generation workflow introduced in this PR. This prevents license header checks from flagging custom overlay files that may have different header requirements or are meant to replace generated code.

client-go/hack/overlays/client/versioned/clientset.go (1)

1-83: LGTM!

This clientset implementation follows Kubernetes client-go conventions with proper nil checks, config shallow-copying to prevent mutation, and clean error propagation. The constructor patterns (NewForConfig, NewForConfigAndClient, NewForConfigOrDie, New) provide flexibility for different use cases.

.versions.yaml (1)

49-50: LGTM!

The added tool versions are appropriate for the code generation workflow. The kubernetes_code_gen version aligns with the Kubernetes v0.34 release family used by client-go dependencies, and goverter v1.9.2 is the latest stable release.

client-go/examples/README.md (1)

1-38: LGTM!

This README provides clear, well-structured documentation for the example suite. The table-based overview effectively organizes examples by complexity, and the prerequisites section clearly explains the fake server requirement for local testing.

api/device/v1alpha1/doc.go (1)

1-19: LGTM!

This package documentation follows Go conventions with a proper license header and Kubebuilder group annotation for code generation. The package-level doc comment clearly describes the API group's purpose.

api/device/v1alpha1/gpu_conversion_test.go (1)

1-153: LGTM!

These conversion tests are comprehensive and well-structured. They properly validate nil handling, round-trip conversion integrity using protocmp.Transform(), and specific field mappings like name lowercasing and ResourceVersion propagation. The use of timestamppb for time values and nested condition structures demonstrates thorough coverage.

client-go/examples/basic-client/main.go (2)

30-47: LGTM!

The setup logic correctly uses the library constants for target resolution and properly initializes the clientset with error handling. The structured logging via stdr aligns with coding guidelines.


49-82: LGTM!

The GPU listing, fetching, and status inspection logic is well-structured. Good use of meta.IsStatusConditionTrue for Kubernetes-style condition checks and meaningful variable naming (isReady).

api/go.mod (1)

3-3: LGTM!

The Go version bump to 1.25.5 and the addition of go-cmp as a direct dependency along with the Kubernetes ecosystem indirect dependencies are appropriate for supporting the new API types and conversions.

Also applies to: 6-6, 19-33

client-go/go.mod (2)

1-15: LGTM!

The module declaration, Go version, replace directive for the local api module, and direct dependencies are properly configured. Kubernetes dependencies are consistently aligned at v0.34.1, and the controller-runtime version is compatible.


17-74: Indirect dependencies are appropriate.

The transitive dependencies from Kubernetes client-go and controller-runtime are expected. Version alignment looks consistent across the K8s ecosystem modules.

api/proto/device/v1alpha1/gpu.proto (3)

27-51: LGTM on message structure!

The ObjectMeta and ListMeta messages correctly implement the Kubernetes metadata pattern for optimistic concurrency. The Gpu and GpuList messages follow the standard Kubernetes resource model (metadata/spec/status). Field documentation is comprehensive as required by coding guidelines.

Also applies to: 61-78


80-117: Well-designed Condition message.

The Condition message correctly follows the Kubernetes condition pattern with appropriate fields (type, status, last_transition_time, reason, message). The use of google.protobuf.Timestamp for last_transition_time is appropriate.


152-167: LGTM on request messages!

Adding resource_version to ListGpusRequest and WatchGpusRequest enables clients to list resources at a specific version and establish Watch streams from a consistent point, following Kubernetes API conventions.

client-go/examples/controller-shim/main.go (1)

80-101: LGTM on NewInformer implementation!

The NewInformer function correctly returns the gRPC-backed informer for GPU objects and falls back to a standard SharedIndexInformer for other types. The indexer merging logic properly handles conflicts by preferring existing implementations.

client-go/nvgrpc/watcher_test.go (4)

31-58: LGTM! Well-structured test for normal event flow.

The test correctly validates the watcher's handling of ADDED, MODIFIED, and DELETED events in sequence. Good use of channel-based event injection.


60-83: Good coverage for unknown event type handling.

Verifies that unknown event types are silently skipped while subsequent valid events are still processed correctly.


85-118: Well-designed table-driven test for error scenarios.

Good use of table-driven testing pattern as per coding guidelines. The test cases cover important gRPC error code mappings (Internal, OutOfRange, InvalidArgument) and verify the correct translation to Kubernetes metav1.Status.


179-239: Test utilities are well-designed and correctly implement the Source interface.

FakeObject properly implements runtime.Object via DeepCopyObject(), and FakeSource correctly handles the event/error injection patterns needed for testing. The Close() method properly handles the double-close case.

api/device/v1alpha1/gpu_types.go (1)

21-70: LGTM! Well-structured Kubernetes API types.

The type definitions follow Kubernetes API conventions correctly:

  • Proper use of metav1.TypeMeta and metav1.ObjectMeta embedding
  • Appropriate codegen markers for client generation (+genclient, +genclient:nonNamespaced, +genclient:onlyVerbs)
  • Correct +k8s:deepcopy-gen:interfaces marker for runtime.Object implementation
  • Good documentation on the UUID format in GPUSpec
client-go/nvgrpc/watcher.go (5)

32-46: Well-designed Source interface and Watcher struct.

The Source interface provides a clean abstraction for event sources, and the Watcher struct correctly uses sync.Once for idempotent shutdown as addressed from previous review feedback.


48-64: LGTM! Constructor properly initializes and starts the receive loop.

The buffered channel (size 100) provides reasonable backpressure handling, and the background goroutine is correctly started.


66-81: Clean idempotent Stop implementation.

Good use of sync.Once to ensure safe concurrent calls to Stop(). The logging at V(4) level is appropriate for operational debugging.


83-136: Solid receive loop implementation with proper shutdown handling.

The implementation correctly:

  • Defers both cleanup (close(w.result)) and Stop() to ensure resources are released
  • Handles io.EOF and codes.Canceled as normal stream closure
  • Maps event types appropriately and skips unknown types
  • Checks w.done before sending to prevent blocking on a stopped watcher

138-170: Good gRPC-to-Kubernetes error code mapping.

The sendError function correctly maps gRPC status codes to Kubernetes metav1.Status reasons. The mapping of OutOfRange, ResourceExhausted, and InvalidArgument to HTTP 410 (Expired) is important for triggering Informer re-list behavior.

api/Makefile (6)

19-41: LGTM! Well-organized variable definitions.

The string manipulation helpers and API package variables are correctly defined. The API_PKGS_COMMA variable (line 37) properly addresses the previously flagged missing variable issue.

Minor: Line 36 is missing a space after # in the comment for consistency.


55-59: Good fallback for GO_VERSION resolution.

Properly attempts to read from go.mod first, then falls back to go env GOVERSION. This ensures consistent toolchain behavior across environments.


96-109: LGTM! Code generation workflow is well-structured.

The code-gen target correctly orchestrates tool installation and all generation steps, followed by go mod tidy to synchronize dependencies.


111-125: Proto generation loop is correct.

The $(foreach) loop properly iterates over API_VERSIONS and generates protobuf bindings for each version with appropriate protoc flags.


127-141: Code generation targets are well-defined.

Both deepcopy-gen and conversion-gen targets correctly use the package variables and iterate over versions as needed.


190-205: LGTM! go-install-tool macro with GOTOOLCHAIN.

The macro correctly uses GOTOOLCHAIN=$(GO_VERSION) to ensure tools are installed with the expected Go version, and implements version-specific binary caching with symlinks.

client-go/examples/fake-server/main.go (5)

42-91: LGTM! Well-structured server initialization and graceful shutdown.

The main function correctly:

  • Resolves the socket path from environment or default
  • Creates the socket directory and cleans stale sockets
  • Sets up signal handling for graceful shutdown
  • Cleans up the socket file on exit

93-128: Good fake server initialization with realistic GPU state.

The newFakeServer properly initializes 8 GPUs with unique UUIDs and initial Ready conditions. The structure mirrors the actual API types well.


130-175: Simulation and broadcast logic is appropriate for a fake server.

The simulateChanges goroutine properly increments resource versions and toggles conditions. The non-blocking send in broadcast() is acceptable for a test server to avoid blocking on slow consumers.


205-255: WatchGpus implementation follows correct streaming patterns.

The implementation correctly:

  • Sends initial ADDED events for all GPUs
  • Registers for updates via a listener channel
  • Cleans up the listener on disconnect via defer
  • Handles context cancellation gracefully

257-263: UUID generation is acceptable for a fake server.

Using math/rand instead of crypto/rand is fine for this test utility. The UUID format follows the GPU-prefixed pattern documented in GPUSpec.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (4)

1-13: LGTM on imports and package declaration.

The imports are appropriately organized with standard library, internal packages, and external dependencies. The import alias for context is redundant but harmless.


58-71: Only ResourceVersion is used from ListOptions.

The method only passes opts.ResourceVersion to the gRPC request, ignoring other ListOptions fields like LabelSelector, FieldSelector, Limit, and Continue. This is likely intentional given the gRPC API design, but consider documenting which options are supported to set caller expectations.


35-41: No issues found. The ClientConn() method is properly implemented on DeviceV1alpha1Client and correctly called in the newGPUs constructor.


73-87: Context cancellation and gpuStreamAdapter implementation verified.

The Watch method correctly implements context cleanup: cancel() is called on error before returning, and the cancellation function is passed to nvgrpc.NewWatcher for cleanup during normal shutdown. The gpuStreamAdapter struct implements the nvgrpc.Source interface with both required methods—Next() returns (string, runtime.Object, error) and Close() returns error—matching the interface definition in nvgrpc/watcher.go.

client-go/Makefile (4)

54-67: Well-structured shell and Go version configuration.

Good practices:

  • Shell configured with pipefail for proper error propagation
  • GO_VERSION extraction with fallback to go env GOVERSION handles both go.mod toolchain directive and environments without it

74-79: Good fail-fast behavior with helpful error message.

The yq dependency check provides clear installation instructions for developers, which is a good UX practice for required build tools.


100-114: Targets are well-structured with appropriate code exclusions.

The build and test targets correctly exclude overlay templates and examples from compilation/testing since overlays are templates and examples may have different build requirements.


198-213: Well-designed tool installation macro.

The go-install-tool macro implements a solid pattern:

  • Version-specific binary naming ($(1)-$(3)) prevents conflicts
  • Symlinks allow seamless version switching
  • GOTOOLCHAIN=$(GO_VERSION) ensures consistent Go version during installation
  • Skips download if versioned binary already exists

Copy link
Contributor

@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: 5

♻️ Duplicate comments (9)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (2)

1-11: Missing package-level godoc.

This issue was previously flagged. The coding guidelines require package-level documentation for all Go packages.

As per coding guidelines.


13-15: Missing function comment for exported method.

This issue was previously flagged. The coding guidelines require function comments for all exported Go functions.

As per coding guidelines.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1)

37-44: Validate the config in NewForConfigAndClient.

This issue was previously flagged. The function accepts a config but doesn't validate it, potentially allowing invalid configurations to propagate.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1)

25-27: CloseSend() is not appropriate for server-streaming RPCs.

This issue was previously flagged. For server-streaming RPCs like WatchGpus, the client only receives messages. Calling CloseSend() is incorrect and should either return nil directly or rely on context cancellation.

client-go/examples/streaming-daemon/main.go (1)

146-148: Fix misleading log message.

This issue was previously flagged. The log message says "context timeout reached" but the context is created with signal.NotifyContext (line 93) and cancels on OS signals, not on timeout.

api/proto/device/v1alpha1/gpu.proto (1)

35-37: Inconsistent indentation in comment block.

Lines 35-37 use tab characters while surrounding lines use spaces. This creates inconsistent formatting.

🔎 Proposed fix
   // resource_version represents the internal version of this object.
   //
   // Value must be treated as opaque by clients and passed unmodified back to the server.
-	// Populated by the system.
-	// Read-only.
-	// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
+  // Populated by the system.
+  // Read-only.
+  // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
   string resource_version = 2;
client-go/hack/overlays/client/versioned/integration_test.go (1)

209-213: Avoid calling t.Errorf from a goroutine.

Calling t.Errorf from a goroutine is unsafe and can cause race conditions or panics if the test completes before the goroutine executes. Since c.Start blocks until context cancellation and errors typically only occur on shutdown, consider logging the error instead or using an error channel.

🔎 Suggested fix using error channel
+		errCh := make(chan error, 1)
 		go func() {
 			if err := c.Start(ctx); err != nil {
-				t.Errorf("Cache failed to start: %v", err)
+				errCh <- err
 			}
+			close(errCh)
 		}()
client-go/examples/fake-server/main.go (1)

199-207: ListMeta is not populated in the response.

The GpuList response doesn't include metadata.resource_version, which is needed for clients to establish a watch from a consistent point (List-then-Watch pattern). Consider tracking a global version and populating it.

🔎 Suggested fix
 	gpuList := &pb.GpuList{
+		Metadata: &pb.ListMeta{
+			ResourceVersion: "1", // Or track a global version
+		},
 		Items: make([]*pb.Gpu, 0, len(s.gpus)),
 	}
client-go/Makefile (1)

187-187: Declare the tools target as .PHONY.

The tools target doesn't produce a file and should be declared .PHONY to ensure it always runs when invoked.

🔎 Proposed fix
+.PHONY: tools
 tools: $(CLIENT_GEN) $(LISTER_GEN) $(INFORMER_GEN)
🧹 Nitpick comments (7)
client-go/nvgrpc/options_test.go (1)

48-64: Use testify assertions for better test readability.

The test assertions currently use plain t.Errorf, but the coding guidelines specify using testify/assert and testify/require for Go tests. This improves readability and provides clearer failure messages.

As per coding guidelines.

🔎 Suggested refactor using testify
+import (
+	"github.com/stretchr/testify/assert"
+)
+
 	t.Run("Logger is correctly assigned", func(t *testing.T) {
-		if dOpts.logger != testLogger {
-			t.Errorf("expected logger to be set, got %v", dOpts.logger)
-		}
+		assert.Equal(t, testLogger, dOpts.logger, "logger should be correctly assigned")
 	})
 
 	t.Run("Unary interceptors are correctly appended", func(t *testing.T) {
-		if len(dOpts.unaryInterceptors) != 2 {
-			t.Errorf("expected 2 unary interceptors, got %d", len(dOpts.unaryInterceptors))
-		}
+		assert.Len(t, dOpts.unaryInterceptors, 2, "should have 2 unary interceptors")
 	})
 
 	t.Run("Stream interceptors are correctly appended", func(t *testing.T) {
-		if len(dOpts.streamInterceptors) != 2 {
-			t.Errorf("expected 2 stream interceptors, got %d", len(dOpts.streamInterceptors))
-		}
+		assert.Len(t, dOpts.streamInterceptors, 2, "should have 2 stream interceptors")
 	})
client-go/nvgrpc/watcher_test.go (2)

31-33: Optional: Unused context variable in some tests.

In TestWatcher_NormalEvents, TestWatcher_UnknownEventType_Ignored, TestWatcher_Errors subtests, and TestWatcher_ErrorTerminatesStream, the ctx variable from context.WithCancel() is created but never used directly (only the cancel function is used). Consider using _ instead:

_, cancel := context.WithCancel(context.Background())

Note: TestWatcher_Stop correctly uses ctx to verify cancellation, so no change needed there.

Also applies to: 60-62, 97-100, 120-122


197-239: Optional: Document thread-safety limitations of FakeSource.

The FakeSource implementation is not thread-safe (particularly the errs slice manipulation in lines 212-216). While this is acceptable since the watcher calls Next() from a single goroutine (go w.receive()), consider adding a comment documenting this limitation to prevent misuse in future tests.

🔎 Suggested documentation
-// FakeSource implements nvgrpc.Source.
+// FakeSource implements nvgrpc.Source for testing.
+// Note: FakeSource is not thread-safe and should only be used
+// with sequential calls to Next() from a single goroutine.
 type FakeSource struct {
 	events chan testEvent
 	errs   []error
 	done   chan struct{}
 }
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1)

20-22: Add function comment for exported method.

The coding guidelines require function comments for all exported Go functions. Add a comment describing what GPUs() returns.

As per coding guidelines.

🔎 Suggested documentation
+// GPUs returns a GPUInterface for interacting with GPU resources
+// in the device.nvidia.com v1alpha1 API group.
 func (c *DeviceV1alpha1Client) GPUs() GPUInterface {
 	return newGPUs(c)
 }
client-go/hack/overlays/client/versioned/clientset.go (1)

1-1: Add package-level documentation.

Per coding guidelines, package-level godoc is required. Add a package comment describing the purpose of this overlay clientset.

🔎 Proposed fix
+// Package versioned provides a versioned clientset for the NVIDIA Device API.
+// It wraps the generated client code with gRPC transport configuration,
+// enabling communication over Unix Domain Sockets.
 package versioned
api/Makefile (2)

111-125: Protobuf generation loop is functional but could be more robust.

The $(foreach) loop will continue even if protoc fails for one version. Consider adding explicit error handling or using a shell loop with proper exit codes for multi-version generation.


36-37: Minor: Missing space after # in comment.

For consistency with other comments in the file, add a space after #.

🔎 Proposed fix
-#Helper for tools that need comma-separated package paths
+# Helper for tools that need comma-separated package paths
 API_PKGS_COMMA := $(subst $(SPACE),$(COMMA),$(API_PKGS))
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3806f19 and 4f3e806.

⛔ Files ignored due to path filters (28)
  • api/device/v1alpha1/zz_generated.conversion.go is excluded by !api/**/zz_generated.*
  • api/device/v1alpha1/zz_generated.deepcopy.go is excluded by !api/**/zz_generated.*
  • api/gen/go/device/v1alpha1/gpu.pb.go is excluded by !**/*.pb.go, !**/gen/**, !api/gen/**
  • api/go.sum is excluded by !**/*.sum
  • client-go/client/versioned/clientset.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/clientset_generated.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/register.go is excluded by !client-go/client/**
  • client-go/client/versioned/integration_test.go is excluded by !client-go/client/**
  • client-go/client/versioned/scheme/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/scheme/register.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/device_client.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_gpu.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/generated_expansion.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/gpu.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go is excluded by !client-go/client/**
  • client-go/go.sum is excluded by !**/*.sum
  • client-go/informers/externalversions/device/interface.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/device/v1alpha1/gpu.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/device/v1alpha1/interface.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/factory.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/generic.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go is excluded by !client-go/informers/**
  • client-go/listers/device/v1alpha1/expansion_generated.go is excluded by !client-go/listers/**
  • client-go/listers/device/v1alpha1/gpu.go is excluded by !client-go/listers/**
📒 Files selected for processing (48)
  • .coderabbit.yaml (1 hunks)
  • .gitignore (1 hunks)
  • .versions.yaml (1 hunks)
  • Makefile (1 hunks)
  • api/Makefile (5 hunks)
  • api/device/v1alpha1/converter.go (1 hunks)
  • api/device/v1alpha1/doc.go (1 hunks)
  • api/device/v1alpha1/gpu_conversion.go (1 hunks)
  • api/device/v1alpha1/gpu_conversion_test.go (1 hunks)
  • api/device/v1alpha1/gpu_types.go (1 hunks)
  • api/device/v1alpha1/register.go (1 hunks)
  • api/go.mod (2 hunks)
  • api/hack/boilerplate.go.txt (1 hunks)
  • api/proto/device/v1alpha1/gpu.proto (4 hunks)
  • client-go/DEVELOPMENT.md (1 hunks)
  • client-go/Makefile (1 hunks)
  • client-go/README.md (1 hunks)
  • client-go/examples/README.md (1 hunks)
  • client-go/examples/basic-client/README.md (1 hunks)
  • client-go/examples/basic-client/main.go (1 hunks)
  • client-go/examples/controller-shim/README.md (1 hunks)
  • client-go/examples/controller-shim/main.go (1 hunks)
  • client-go/examples/fake-server/README.md (1 hunks)
  • client-go/examples/fake-server/main.go (1 hunks)
  • client-go/examples/streaming-daemon/README.md (1 hunks)
  • client-go/examples/streaming-daemon/main.go (1 hunks)
  • client-go/go.mod (1 hunks)
  • client-go/hack/apply-overlays.sh (1 hunks)
  • client-go/hack/boilerplate.go.txt (1 hunks)
  • client-go/hack/boilerplate_overlay.go.txt (1 hunks)
  • client-go/hack/overlays/client/versioned/clientset.go (1 hunks)
  • client-go/hack/overlays/client/versioned/integration_test.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (1 hunks)
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1 hunks)
  • client-go/nvgrpc/client_conn.go (1 hunks)
  • client-go/nvgrpc/client_conn_test.go (1 hunks)
  • client-go/nvgrpc/config.go (1 hunks)
  • client-go/nvgrpc/config_test.go (1 hunks)
  • client-go/nvgrpc/interceptors.go (1 hunks)
  • client-go/nvgrpc/interceptors_test.go (1 hunks)
  • client-go/nvgrpc/options.go (1 hunks)
  • client-go/nvgrpc/options_test.go (1 hunks)
  • client-go/nvgrpc/watcher.go (1 hunks)
  • client-go/nvgrpc/watcher_test.go (1 hunks)
  • client-go/version/version.go (1 hunks)
  • client-go/version/version_test.go (1 hunks)
✅ Files skipped from review due to trivial changes (4)
  • client-go/examples/streaming-daemon/README.md
  • client-go/hack/boilerplate_overlay.go.txt
  • client-go/examples/README.md
  • api/hack/boilerplate.go.txt
🚧 Files skipped from review as they are similar to previous changes (23)
  • client-go/version/version_test.go
  • client-go/examples/basic-client/main.go
  • client-go/go.mod
  • .coderabbit.yaml
  • api/device/v1alpha1/doc.go
  • client-go/examples/controller-shim/main.go
  • client-go/examples/fake-server/README.md
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go
  • client-go/nvgrpc/interceptors_test.go
  • api/device/v1alpha1/gpu_types.go
  • client-go/nvgrpc/config.go
  • client-go/nvgrpc/watcher.go
  • api/device/v1alpha1/register.go
  • client-go/nvgrpc/interceptors.go
  • client-go/nvgrpc/client_conn.go
  • client-go/nvgrpc/client_conn_test.go
  • client-go/nvgrpc/config_test.go
  • client-go/version/version.go
  • api/go.mod
  • client-go/examples/controller-shim/README.md
  • client-go/hack/boilerplate.go.txt
  • Makefile
  • client-go/README.md
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.go: Follow standard Go conventions with gofmt and golint
Use structured logging via log/slog in Go code
Wrap errors with context using fmt.Errorf("context: %w", err) in Go code
Within retry.RetryOnConflict blocks, return errors without wrapping to preserve retry behavior
Use meaningful variable names such as synced over ok for cache sync checks
Use client-go for Kubernetes API interactions in Go code
Prefer informers over direct API calls for watching Kubernetes resources
Implement proper shutdown handling with context cancellation in Go code
Package-level godoc required for all Go packages
Function comments required for all exported Go functions
Use inline comments for complex logic only in Go code
TODO comments should reference issues in Go code
Extract informer event handler setup into helper methods
Use separate informers for different Kubernetes resource types

Files:

  • client-go/examples/streaming-daemon/main.go
  • api/device/v1alpha1/gpu_conversion.go
  • client-go/examples/fake-server/main.go
  • client-go/nvgrpc/options.go
  • client-go/hack/overlays/client/versioned/clientset.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go
  • api/device/v1alpha1/converter.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/nvgrpc/options_test.go
  • api/device/v1alpha1/gpu_conversion_test.go
  • client-go/nvgrpc/watcher_test.go
  • client-go/hack/overlays/client/versioned/integration_test.go
**/*_test.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*_test.go: Use envtest for testing Kubernetes controllers instead of fake clients
Use testify/assert and testify/require for assertions in Go tests
Write table-driven tests when testing multiple scenarios in Go
Name Go tests descriptively using format: TestFunctionName_Scenario_ExpectedBehavior

Files:

  • client-go/nvgrpc/options_test.go
  • api/device/v1alpha1/gpu_conversion_test.go
  • client-go/nvgrpc/watcher_test.go
  • client-go/hack/overlays/client/versioned/integration_test.go
🧠 Learnings (16)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Package-level godoc required for all Go packages

Applied to files:

  • client-go/examples/streaming-daemon/main.go
  • client-go/examples/fake-server/main.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Implement proper shutdown handling with context cancellation in Go code

Applied to files:

  • client-go/examples/streaming-daemon/main.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go
  • client-go/hack/overlays/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code

Applied to files:

  • .gitignore
  • client-go/examples/basic-client/README.md
  • .versions.yaml
  • client-go/hack/apply-overlays.sh
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • api/Makefile
  • client-go/DEVELOPMENT.md
  • client-go/Makefile
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Follow standard Go conventions with gofmt and golint

Applied to files:

  • .gitignore
  • .versions.yaml
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Use `envtest` for testing Kubernetes controllers instead of fake clients

Applied to files:

  • .gitignore
  • .versions.yaml
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/nvgrpc/watcher_test.go
  • client-go/hack/overlays/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Keep Go dependencies minimal and up-to-date

Applied to files:

  • .versions.yaml
  • api/Makefile
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Function comments required for all exported Go functions

Applied to files:

  • client-go/examples/fake-server/main.go
  • client-go/nvgrpc/options.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to data-models/protobufs/**/*.proto : Include comprehensive comments for all fields in Protocol Buffer messages

Applied to files:

  • api/proto/device/v1alpha1/gpu.proto
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to data-models/protobufs/**/*.proto : Use semantic versioning for breaking changes in Protocol Buffer messages

Applied to files:

  • api/proto/device/v1alpha1/gpu.proto
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : TODO comments should reference issues in Go code

Applied to files:

  • client-go/nvgrpc/options.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
📚 Learning: 2025-11-04T06:31:02.147Z
Learnt from: Gyan172004
Repo: NVIDIA/NVSentinel PR: 223
File: platform-connectors/pkg/nodemetadata/processor.go:0-0
Timestamp: 2025-11-04T06:31:02.147Z
Learning: In platform-connectors/pkg/nodemetadata/processor.go, the NewProcessor function does not perform a nil check on the config parameter because the caller is expected to guarantee a non-nil config is provided.

Applied to files:

  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Name Go tests descriptively using format: `TestFunctionName_Scenario_ExpectedBehavior`

Applied to files:

  • api/device/v1alpha1/gpu_conversion_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use meaningful variable names such as `synced` over `ok` for cache sync checks

Applied to files:

  • client-go/hack/overlays/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use separate informers for different Kubernetes resource types

Applied to files:

  • client-go/hack/overlays/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Prefer informers over direct API calls for watching Kubernetes resources

Applied to files:

  • client-go/hack/overlays/client/versioned/integration_test.go
🧬 Code graph analysis (9)
api/device/v1alpha1/gpu_conversion.go (2)
api/device/v1alpha1/converter.go (1)
  • Converter (30-104)
api/device/v1alpha1/gpu_types.go (2)
  • GPU (55-61)
  • GPUList (67-71)
client-go/examples/fake-server/main.go (3)
client-go/nvgrpc/config.go (2)
  • NvidiaDeviceAPITargetEnvVar (28-28)
  • DefaultNvidiaDeviceAPISocket (31-31)
api/device/v1alpha1/gpu_types.go (3)
  • GPU (55-61)
  • GPUSpec (24-30)
  • GPUStatus (35-45)
api/device/v1alpha1/gpu_conversion.go (1)
  • ToProto (35-40)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (1)
  • GPUInterface (22-27)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1)
api/device/v1alpha1/gpu_conversion.go (1)
  • FromProto (25-32)
api/device/v1alpha1/converter.go (2)
api/device/v1alpha1/gpu_types.go (4)
  • GPU (55-61)
  • GPUList (67-71)
  • GPUSpec (24-30)
  • GPUStatus (35-45)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
client-go/nvgrpc/options_test.go (1)
client-go/nvgrpc/options.go (4)
  • DialOption (23-23)
  • WithLogger (32-36)
  • WithUnaryInterceptor (39-43)
  • WithStreamInterceptor (46-50)
api/device/v1alpha1/gpu_conversion_test.go (1)
api/device/v1alpha1/gpu_conversion.go (4)
  • FromProto (25-32)
  • ToProto (35-40)
  • FromProtoList (43-48)
  • ToProtoList (51-56)
client-go/nvgrpc/watcher_test.go (1)
client-go/nvgrpc/watcher.go (1)
  • NewWatcher (49-64)
client-go/hack/overlays/client/versioned/integration_test.go (4)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/hack/overlays/client/versioned/clientset.go (2)
  • NewForConfigAndClient (48-65)
  • New (79-83)
api/device/v1alpha1/gpu_types.go (1)
  • GPU (55-61)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
🪛 checkmake (0.2.2)
client-go/Makefile

[warning] 187-187: Target "tools" should be declared PHONY.

(phonydeclared)

🪛 LanguageTool
client-go/DEVELOPMENT.md

[style] ~77-~77: This phrase is redundant. Consider using “inside”.
Context: ... informers/) The directory structure inside of hack/overlays/ *must exactly mirror...

(OUTSIDE_OF)

🪛 markdownlint-cli2 (0.18.1)
client-go/DEVELOPMENT.md

10-10: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


11-11: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (23)
  • GitHub Check: ko-build-test (health-monitors/csp-health-monitor, ./cmd/maintenance-notifier)
  • GitHub Check: ko-build-test (janitor, .)
  • GitHub Check: container-build-test (gpu-health-monitor-dcgm3, make -C health-monitors/gpu-health-monitor docker...
  • GitHub Check: container-build-test (gpu-health-monitor-dcgm4, make -C health-monitors/gpu-health-monitor docker...
  • GitHub Check: container-build-test (file-server-cleanup, make -C log-collector docker-build-file-server-cleanup)
  • GitHub Check: container-build-test (syslog-health-monitor, make -C health-monitors/syslog-health-monitor docker...
  • GitHub Check: container-build-test (log-collector, make -C log-collector docker-build-log-collector)
  • GitHub Check: E2E Tests (ARM64 + MongoDB)
  • GitHub Check: E2E Tests (AMD64 + PostgreSQL)
  • GitHub Check: E2E Tests (AMD64 + MongoDB)
  • GitHub Check: E2E Tests (ARM64 + PostgreSQL)
  • GitHub Check: CodeQL PR Analysis
  • GitHub Check: modules-lint-test (fault-quarantine)
  • GitHub Check: modules-lint-test (labeler)
  • GitHub Check: modules-lint-test (node-drainer)
  • GitHub Check: modules-lint-test (platform-connectors)
  • GitHub Check: modules-lint-test (fault-remediation)
  • GitHub Check: modules-lint-test (health-events-analyzer)
  • GitHub Check: modules-lint-test (janitor)
  • GitHub Check: modules-lint-test (store-client)
  • GitHub Check: health-monitors-lint-test (kubernetes-object-monitor)
  • GitHub Check: health-monitors-lint-test (csp-health-monitor)
  • GitHub Check: health-monitors-lint-test (syslog-health-monitor)
🔇 Additional comments (37)
.gitignore (1)

18-18: LGTM!

The addition correctly mirrors the existing api/bin/* pattern and aligns with the new client-go module's code-generation artifacts. Placement in the Go section is appropriate.

client-go/DEVELOPMENT.md (1)

1-104: Well-structured development guide.

This documentation provides clear, actionable guidance on the code-generation workflow, overlay pattern, and project directory structure. The use of bash examples, a mermaid diagram, and callouts (TIP, WARNING) makes it accessible to developers unfamiliar with the SDK. The documentation aligns well with the PR objectives and supports the maintainability of the client-go module.

client-go/nvgrpc/options.go (1)

22-50: LGTM! Functional options pattern correctly implemented.

The code properly implements the functional options pattern for gRPC client configuration:

  • All exported types and functions have appropriate godoc comments (as per coding guidelines)
  • Interceptor functions correctly append to slices, supporting multiple interceptors
  • Logger configuration is straightforward and correct
  • The pattern integrates well with the ClientConnFor usage shown in the context
.versions.yaml (1)

49-50: LGTM!

The tool versions are appropriate. Goverter v1.9.2 is the latest release, and kubernetes_code_gen v0.34.1 matches the client-go version in use, ensuring compatibility within the same Kubernetes release family.

client-go/hack/apply-overlays.sh (1)

1-29: LGTM!

The script has proper error handling with set -euo pipefail, validates prerequisites (boilerplate file and repository root), and correctly applies overlays by concatenating boilerplate with source files.

api/device/v1alpha1/gpu_conversion_test.go (1)

30-153: LGTM!

The tests comprehensively cover nil handling and round-trip conversions for both GPU and GPUList types. The use of protocmp.Transform() for protobuf comparison is the correct approach, and the tests validate critical fields like name lowercasing and ResourceVersion propagation.

api/device/v1alpha1/gpu_conversion.go (1)

15-56: LGTM!

The conversion helpers are well-implemented with proper nil checks, clear godoc comments, and consistent delegation to the converter singleton. The build tag !goverter appropriately guards against conflicts with generated code.

client-go/examples/streaming-daemon/main.go (1)

15-145: LGTM!

The example demonstrates proper gRPC client setup with custom interceptors, signal-based shutdown handling, and both unary (List) and streaming (Watch) operations. The package documentation is clear and the code follows best practices for context management and error handling.

api/proto/device/v1alpha1/gpu.proto (2)

27-51: Good Kubernetes-native metadata design.

The ObjectMeta and ListMeta messages properly mirror Kubernetes API machinery patterns with resource_version for optimistic concurrency control. The Gpu and GpuList structures correctly embed these metadata types.

Also applies to: 61-78


152-167: Correct implementation of resource versioning for List/Watch.

Adding resource_version to both ListGpusRequest and WatchGpusRequest enables the List-then-Watch pattern, allowing clients to establish watches from a consistent point in time. This aligns with Kubernetes API conventions.

client-go/hack/overlays/client/versioned/integration_test.go (4)

33-62: Well-structured test setup with proper resource cleanup.

The test setup correctly uses bufconn for in-process gRPC testing, establishes a context with timeout, and properly defers cleanup with s.Stop() and conn.Close(). This follows good testing patterns.


64-129: Comprehensive Get/List/Watch flow testing.

The subtests properly validate the core client operations with appropriate timeout handling. The Watch test correctly verifies both initial snapshot (ADDED event) and live updates (MODIFIED event).


131-182: Proper informer lifecycle management.

The test correctly instantiates the informer before starting the factory, uses cache.WaitForCacheSync for synchronization, and employs wait.PollUntilContextTimeout for verifying asynchronous cache updates.


256-336: Thread-safe mock server with proper watch semantics.

The mock server correctly implements thread-safe access with sync.RWMutex, sends an initial snapshot of ADDED events, and properly handles context cancellation in the watch stream. The buffered channel prevents blocking during event dispatch.

client-go/examples/fake-server/main.go (6)

15-20: Package documentation present as required.

The package-level godoc properly documents the fake server's purpose and behavior.


47-96: Proper server lifecycle management with graceful shutdown.

The main function correctly handles socket setup, stale socket cleanup, and graceful shutdown via signal handling. Using nvgrpc.NvidiaDeviceAPITargetEnvVar and nvgrpc.DefaultNvidiaDeviceAPISocket constants ensures consistency with the client SDK.


98-133: Clean separation of internal types from protobuf wire format.

Using devicev1alpha1.GPU internally and converting to protobuf at the API boundary is the correct pattern. The initialization properly sets up GPU conditions with meaningful defaults.


137-180: Correct simulation with non-blocking broadcast.

The simulateChanges function properly increments ResourceVersion for watch semantics, uses DeepCopy to prevent data races, and the non-blocking broadcast pattern prevents slow consumers from blocking the simulation loop.


210-260: Correct watch stream implementation with proper lifecycle management.

The WatchGpus method correctly sends an initial snapshot of ADDED events, registers for updates, handles context cancellation, and cleans up the listener on exit. The anonymous function pattern for the initial snapshot ensures proper lock scope.


262-268: UUID generation is acceptable for this fake server context.

While math/rand is not cryptographically secure, it's appropriate for a local testing fake server. The UUID version 4 bit manipulation is correct.

client-go/hack/overlays/client/versioned/clientset.go (2)

12-24: Clean interface design following client-go patterns.

The Interface and Clientset struct properly follow Kubernetes client-go conventions, enabling easy mocking and dependency injection.


26-83: Well-designed constructor variants with proper validation.

The constructors follow established client-go patterns:

  • Defensive nil checks prevent runtime errors
  • Config shallow-copying prevents external mutation
  • NewForConfigOrDie pattern is idiomatic for startup code
  • New provides a simple escape hatch for pre-configured connections
api/device/v1alpha1/converter.go (2)

23-104: Well-designed bidirectional converter interface with goverter annotations.

The Converter interface properly defines bidirectional conversion between protobuf and Kubernetes types. The goverter annotations correctly:

  • Map field name differences (e.g., UuidUUID, MetadataObjectMeta)
  • Ignore Kubernetes-specific fields not present in protobuf (e.g., Namespace, GenerateName)
  • Ignore protobuf internal fields (state, sizeCache, unknownFields)

106-133: Correct TypeMeta and Timestamp conversion helpers.

The FromProtobufTypeMeta and FromProtobufListTypeMeta functions now correctly use SchemeGroupVersion.String() to produce the full group/version format (device.nvidia.com/v1alpha1). The timestamp conversion properly handles nil values.

client-go/Makefile (7)

1-14: License header looks good.

Standard Apache 2.0 license header is correctly applied.


19-47: Configuration variables are well-structured.

The string manipulation helpers and module/version configuration follow standard Makefile patterns. The LDFLAGS construction with version injection is correct.


54-67: Shell and Go version setup is correct.

The bash pipefail setup and Go version extraction with fallback are well-implemented.


74-84: Tool version management is well-implemented.

The centralized version file approach with yq parsing ensures consistent tooling across the project. The early failure on missing yq is helpful for developer experience.


100-104: Code generation workflow is correctly structured.

The dependency chain ensures tools are installed first, then client code is generated, overlays are applied, and finally listers/informers are generated. Running go mod tidy at the end properly synchronizes dependencies.


198-213: Tool installation macro is well-designed.

The versioned binary approach with symlinks is a robust pattern that handles upgrades gracefully and allows version coexistence. Using GOTOOLCHAIN ensures consistent Go toolchain usage.


110-113: Grep exclusion patterns work correctly; inconsistency is harmless.

The pattern inconsistency noted (/listers/ vs informers/ without leading slash) does not cause incorrect filtering because there are no listers/ or informers/ directories in this repository. The exclusions for /examples/ and /hack/overlays/ function as intended. If consistency is desired for maintainability, both patterns could use leading slashes: /listers/|/informers/ — but this is not a functional issue.

api/Makefile (6)

19-40: Configuration section is well-structured.

The string manipulation helpers and API version configuration follow the same patterns as client-go/Makefile. The API_PKGS_COMMA definition addresses the previously flagged issue.


76-79: Version management from central YAML file is a good practice.

This ensures consistent tooling versions across the project.


136-141: Conversion generation target is correctly implemented.

The typo with the double period appears to have been addressed. The per-version loop with goverter is appropriate.


143-167: Clean targets are comprehensive and well-organized.

Using find for generated file cleanup is a safe approach that handles files in subdirectories correctly.


171-188: Tool installation targets are correctly implemented.

The installation pattern is consistent across both Makefiles and uses the centralized version management properly.


194-205: GOTOOLCHAIN addition improves build reproducibility.

Pinning the Go toolchain version during tool installation ensures consistent behavior across different environments.

# Downloads codegen tools, generates clients/listers/informers, and applies overlays
make code-gen
```
**Note**: This process runs `hack/apply-overlays.sh` to inject custom gRPC logic into the generated files.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Instead of overlays, do we have other modes of extensions that are possible? Can we call the codegen tools as a library perhaps?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good call out. Using overlays is definitely not the most ideal. Gonna try out a couple ideas and see what might work better here.

**Example**: To customize `client/versioned/clientset.go`, you must edit `hack/overlays/client/versioned/clientset.go`.

> [!WARNING]
> **Do not edit generated files directly.**
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we add a CI check to ensure the files aren't manually edited by the user?

Copy link
Contributor

@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: 4

♻️ Duplicate comments (20)
client-go/version/version.go (1)

15-15: Add package-level godoc comment.

The coding guidelines require package-level godoc for all Go packages. This issue was previously flagged but remains unaddressed.

As per coding guidelines, package-level godoc is required for all Go packages.

🔎 Suggested addition
+// Package version provides build-time version information and user-agent
+// string generation for the nvidia-device-api-client.
 package version
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (2)

1-11: Add package-level godoc comment.

The coding guidelines require package-level documentation for all Go packages. This was already flagged in a previous review.

As per coding guidelines.


13-15: Add function comment for exported method.

The coding guidelines require function comments for all exported Go functions. This was already flagged in a previous review.

As per coding guidelines.

client-go/nvgrpc/watcher_test.go (5)

31-58: Test logic is sound; testify assertions already flagged.

The test correctly validates normal event flow (ADDED, MODIFIED, DELETED) by pre-populating a buffered channel, consuming from ResultChan, and verifying event types. The use of stdlib testing methods (t.Fatalf, t.Errorf) instead of testify/assert and testify/require has already been flagged in a previous review comment.


60-83: Good edge case coverage; testify assertions already flagged.

The test correctly verifies that unknown event types are ignored and subsequent valid events are processed. The testify assertion issue has already been covered in a previous review comment.


85-118: Excellent table-driven structure; testify assertions already flagged.

The test properly uses table-driven design to validate error mapping to Kubernetes metav1.Status with appropriate reason and HTTP codes. The coverage of Internal (500), OutOfRange (410/Expired), and InvalidArgument (410/Expired) scenarios is thorough. The testify assertion issue has already been flagged in a previous review comment.


120-152: Correct termination behavior validation; testify assertions already flagged.

The test correctly verifies that the first error terminates the stream and subsequent errors are not delivered. The use of a labeled break (break Receive) is idiomatic for exiting the nested select/for structure. The testify assertion issue has already been flagged in a previous review comment.


154-177: Stop behavior test intent is valid; race condition and testify assertions already flagged.

The test correctly validates that Stop() cancels the context and closes ResultChan. However, the time.Sleep on line 160 introduces a race condition, and the use of stdlib testing methods instead of testify assertions—both issues have been comprehensively addressed in previous review comments.

client-go/examples/controller-shim/main.go (3)

65-69: The informer factory is never started.

The comment on line 67 states the Manager will start the injected informer, but controller-runtime only starts informers it creates through its own cache machinery. The gRPC-backed informer from factory needs to be started explicitly; otherwise, factory-level coordination, proper cache sync, and shutdown may not work correctly.

🔎 Suggested fix

Start the factory using the manager's context before starting the manager:

 	factory := informers.NewSharedInformerFactory(clientset, 10*time.Minute)
 	gpuInformer := factory.Device().V1alpha1().GPUs().Informer()
 
+	ctx := ctrl.SetupSignalHandler()
+	go factory.Start(ctx.Done())
+	
+	// Wait for the informer cache to sync before proceeding
+	if !toolscache.WaitForCacheSync(ctx.Done(), gpuInformer.HasSynced) {
+		setupLog.Error(nil, "failed to sync informer cache")
+		os.Exit(1)
+	}
+
 	// Initialize the controller-runtime Manager.

Then remove the duplicate ctx := ctrl.SetupSignalHandler() from line 121.


135-146: Add godoc comment for exported Reconcile method.

The exported Reconcile method lacks documentation. Coding guidelines require function comments for all exported Go functions, starting with the function name.

🔎 Suggested addition
+// Reconcile retrieves the requested GPU resource from the gRPC-backed cache
+// and logs its name and UUID. It returns without error if the GPU is not found.
 func (r *GPUReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {

As per coding guidelines, function comments are required for all exported Go functions.


148-152: Add godoc comment for exported SetupWithManager method.

The exported SetupWithManager method lacks documentation. Coding guidelines require function comments for all exported Go functions, starting with the function name.

🔎 Suggested addition
+// SetupWithManager registers this reconciler with the provided manager,
+// configuring it to watch GPU resources.
 func (r *GPUReconciler) SetupWithManager(mgr ctrl.Manager) error {

As per coding guidelines, function comments are required for all exported Go functions.

client-go/examples/basic-client/README.md (1)

20-38: Socket path mismatch persists between instructions and expected output.

The environment variable at line 24 sets unix:///tmp/device-api.sock, but the expected output at line 31 shows unix:///tmp/nvidia-device-api.sock. This inconsistency will confuse users trying to reproduce the example.

🔎 Proposed fix
-"level"=0 "msg"="discovered GPUs" "count"=8 "target"="unix:///tmp/nvidia-device-api.sock"
+"level"=0 "msg"="discovered GPUs" "count"=8 "target"="unix:///tmp/device-api.sock"
api/proto/device/v1alpha1/gpu.proto (1)

32-38: Inconsistent indentation persists in ObjectMeta comments.

Lines 35-37 use tabs while surrounding lines use spaces, creating formatting inconsistency.

🔎 Proposed fix
   // resource_version represents the internal version of this object.
   //
   // Value must be treated as opaque by clients and passed unmodified back to the server.
-	// Populated by the system.
-	// Read-only.
-	// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
+  // Populated by the system.
+  // Read-only.
+  // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
   string resource_version = 2;
client-go/DEVELOPMENT.md (2)

10-11: Fix nested list indentation for markdown lint compliance.

The nested list items use 4-space indentation instead of the expected 2 spaces.

🔎 Proposed fix
-    * *macOS*: `brew install yq`
-    * *Linux*: See [yq installation](https://github.com/mikefarah/yq)
+  * *macOS*: `brew install yq`
+  * *Linux*: See [yq installation](https://github.com/mikefarah/yq)

77-77: Remove redundant phrase.

The phrase "inside of" is redundant; use "inside" for conciseness.

🔎 Proposed fix
-The directory structure inside of `hack/overlays/` **must exactly mirror** the structure of the generated code.
+The directory structure inside `hack/overlays/` **must exactly mirror** the structure of the generated code.
client-go/hack/overlays/client/versioned/integration_test.go (1)

209-213: Avoid calling t.Errorf from a goroutine.

Calling t.Errorf (or any t method) from a goroutine is unsafe and can cause race conditions or panics if the test completes before the goroutine executes. Since c.Start blocks until context cancellation and typically only returns errors on shutdown, consider using an error channel or simply logging the error.

🔎 Suggested fix using error channel
+		errCh := make(chan error, 1)
 		go func() {
 			if err := c.Start(ctx); err != nil {
-				t.Errorf("Cache failed to start: %v", err)
+				errCh <- err
 			}
+			close(errCh)
 		}()

Then after the test logic completes, check for errors:

select {
case err := <-errCh:
    if err != nil {
        t.Errorf("Cache failed to start: %v", err)
    }
default:
}
client-go/examples/fake-server/main.go (1)

195-208: ListMeta.ResourceVersion is not populated in the response.

The GpuList response doesn't include Metadata.ResourceVersion, which clients need for the List-then-Watch pattern to establish a watch from a consistent point. Consider tracking a global resource version or deriving it from the highest GPU resource version.

🔎 Suggested fix
 func (s *fakeServer) ListGpus(ctx context.Context, req *pb.ListGpusRequest) (*pb.ListGpusResponse, error) {
 	s.mu.RLock()
 	defer s.mu.RUnlock()

+	// Derive list resource version from the highest GPU resource version
+	var maxRV int
+	for _, gpu := range s.gpus {
+		rv, _ := strconv.Atoi(gpu.ResourceVersion)
+		if rv > maxRV {
+			maxRV = rv
+		}
+	}
+
 	gpuList := &pb.GpuList{
+		Metadata: &pb.ListMeta{
+			ResourceVersion: strconv.Itoa(maxRV),
+		},
 		Items: make([]*pb.Gpu, 0, len(s.gpus)),
 	}
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1)

37-44: Add defensive checks for config parameter.

The function doesn't validate the config parameter, which could lead to panics or invalid client state:

  • No nil check before calling c.GetLogger()
  • No validation of config contents
🔎 Proposed fix
 func NewForConfigAndClient(c *nvgrpc.Config, conn grpc.ClientConnInterface) (*DeviceV1alpha1Client, error) {
+	if c == nil {
+		return nil, fmt.Errorf("config cannot be nil")
+	}
+	if err := c.Validate(); err != nil {
+		return nil, err
+	}
 	return &DeviceV1alpha1Client{
 		conn:   conn,
 		logger: c.GetLogger().WithName("device.v1alpha1"),
 	}, nil
 }
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (1)

21-27: Define the missing GPUExpansion interface.

The GPUInterface embeds GPUExpansion (line 26), but this interface is not defined, which will cause a compilation failure. Following Kubernetes client-go patterns, create a new file gpu_expansion.go in the same directory:

package v1alpha1

// GPUExpansion allows for extension of GPU interface
type GPUExpansion interface{}

This empty interface serves as an extension point for future methods.

client-go/Makefile (1)

187-187: Declare the tools target as PHONY.

The tools target should be declared .PHONY since it doesn't produce a file output and is used as a convenience alias for tool binaries. Without this declaration, Make may incorrectly skip rebuilding if a file named "tools" exists.

🔎 Proposed fix
+.PHONY: tools
 tools: $(CLIENT_GEN) $(LISTER_GEN) $(INFORMER_GEN)
🧹 Nitpick comments (6)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1)

21-23: Consider returning nil directly instead of typed nil.

The current implementation declares a typed *grpc.ClientConn variable and returns it, which creates a non-nil interface containing a nil pointer. This pattern can be confusing because interface nil checks (conn != nil) will pass, but any method call will panic.

For clarity, return nil directly:

🔎 Clearer nil return
 func (c *FakeDeviceV1alpha1) ClientConn() grpc.ClientConnInterface {
-	var ret *grpc.ClientConn
-	return ret
+	return nil
 }
client-go/nvgrpc/options_test.go (1)

25-46: Add test case for default logger behavior.

The AI summary states this test "Verifies that a discard logger is correctly assigned when none is provided," but no such test case exists in the code. Consider adding a test case that verifies the default logger behavior when WithLogger is not called.

🔎 Add test case for default logger
t.Run("Default logger is assigned when none provided", func(t *testing.T) {
	defaultOpts := &dialOptions{}
	// Apply options without WithLogger
	for _, opt := range []DialOption{
		WithUnaryInterceptor(dummyUnary),
	} {
		opt(defaultOpts)
	}
	// Verify default logger is set (implementation-dependent check)
	if defaultOpts.logger.GetSink() == nil {
		t.Errorf("expected default logger to be initialized")
	}
})

Note: You may need to verify how the default logger is initialized in the actual implementation to write an accurate assertion.

api/device/v1alpha1/converter.go (1)

130-133: Consider handling zero-value metav1.Time in ToProtobufTimestamp.

When source.Time is a zero-value, timestamppb.New() returns a Timestamp representing Unix epoch (1970-01-01). This may be acceptable, but if zero-value should represent "unset", consider returning nil instead.

🔎 Optional fix if nil is preferred for zero-value
 func ToProtobufTimestamp(source metav1.Time) *timestamppb.Timestamp {
+	if source.IsZero() {
+		return nil
+	}
 	return timestamppb.New(source.Time)
 }
client-go/hack/overlays/client/versioned/integration_test.go (1)

64-86: Consider using testify/assert for assertions.

Per coding guidelines, use testify/assert and testify/require for assertions in Go tests. This provides better error messages and a consistent assertion style.

🔎 Example refactor for the Get subtest
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
...
 	t.Run("Get", func(t *testing.T) {
 		gpu, err := cs.DeviceV1alpha1().GPUs().Get(ctx, "gpu-1", metav1.GetOptions{})
-		if err != nil {
-			t.Fatalf("Get failed: %v", err)
-		}
-		if gpu.Name != "gpu-1" {
-			t.Errorf("Expected gpu-1, got %s", gpu.Name)
-		}
+		require.NoError(t, err, "Get failed")
+		assert.Equal(t, "gpu-1", gpu.Name)
 	})

Based on coding guidelines, use testify/assert and testify/require for assertions in Go tests.

client-go/examples/fake-server/main.go (1)

182-193: Add function comments for exported methods.

Per coding guidelines, function comments are required for all exported Go functions. The gRPC service methods GetGpu, ListGpus, and WatchGpus should have documentation comments.

🔎 Proposed documentation
+// GetGpu returns a single GPU by name, or NotFound if it doesn't exist.
 func (s *fakeServer) GetGpu(ctx context.Context, req *pb.GetGpuRequest) (*pb.GetGpuResponse, error) {

+// ListGpus returns all GPUs in the fake server's inventory.
 func (s *fakeServer) ListGpus(ctx context.Context, req *pb.ListGpusRequest) (*pb.ListGpusResponse, error) {

+// WatchGpus streams GPU events to the client. It first sends ADDED events for
+// all existing GPUs (initial snapshot), then streams MODIFIED events as the
+// simulated state changes.
 func (s *fakeServer) WatchGpus(req *pb.WatchGpusRequest, stream pb.GpuService_WatchGpusServer) error {

Based on coding guidelines, function comments are required for all exported Go functions.

Also applies to: 195-208, 210-260

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (1)

35-41: Consider nil check for defensive programming.

The constructor doesn't check if c is nil before calling c.ClientConn() and c.logger.WithName(). While this is a private function and callers should provide valid input, a defensive check could prevent panics.

🔎 Optional defensive check
 func newGPUs(c *DeviceV1alpha1Client) *gpus {
+	if c == nil {
+		panic("DeviceV1alpha1Client cannot be nil")
+	}
 	return &gpus{
 		client: pb.NewGpuServiceClient(c.ClientConn()),
 		logger: c.logger.WithName("gpus"),
 	}
 }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4f3e806 and a1fae68.

⛔ Files ignored due to path filters (28)
  • api/device/v1alpha1/zz_generated.conversion.go is excluded by !api/**/zz_generated.*
  • api/device/v1alpha1/zz_generated.deepcopy.go is excluded by !api/**/zz_generated.*
  • api/gen/go/device/v1alpha1/gpu.pb.go is excluded by !**/*.pb.go, !**/gen/**, !api/gen/**
  • api/go.sum is excluded by !**/*.sum
  • client-go/client/versioned/clientset.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/clientset_generated.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/register.go is excluded by !client-go/client/**
  • client-go/client/versioned/integration_test.go is excluded by !client-go/client/**
  • client-go/client/versioned/scheme/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/scheme/register.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/device_client.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_gpu.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/generated_expansion.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/gpu.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go is excluded by !client-go/client/**
  • client-go/go.sum is excluded by !**/*.sum
  • client-go/informers/externalversions/device/interface.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/device/v1alpha1/gpu.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/device/v1alpha1/interface.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/factory.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/generic.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go is excluded by !client-go/informers/**
  • client-go/listers/device/v1alpha1/expansion_generated.go is excluded by !client-go/listers/**
  • client-go/listers/device/v1alpha1/gpu.go is excluded by !client-go/listers/**
📒 Files selected for processing (49)
  • .coderabbit.yaml
  • .gitattributes
  • .gitignore
  • .versions.yaml
  • Makefile
  • api/Makefile
  • api/device/v1alpha1/converter.go
  • api/device/v1alpha1/doc.go
  • api/device/v1alpha1/gpu_conversion.go
  • api/device/v1alpha1/gpu_conversion_test.go
  • api/device/v1alpha1/gpu_types.go
  • api/device/v1alpha1/register.go
  • api/go.mod
  • api/hack/boilerplate.go.txt
  • api/proto/device/v1alpha1/gpu.proto
  • client-go/DEVELOPMENT.md
  • client-go/Makefile
  • client-go/README.md
  • client-go/examples/README.md
  • client-go/examples/basic-client/README.md
  • client-go/examples/basic-client/main.go
  • client-go/examples/controller-shim/README.md
  • client-go/examples/controller-shim/main.go
  • client-go/examples/fake-server/README.md
  • client-go/examples/fake-server/main.go
  • client-go/examples/streaming-daemon/README.md
  • client-go/examples/streaming-daemon/main.go
  • client-go/go.mod
  • client-go/hack/apply-overlays.sh
  • client-go/hack/boilerplate.go.txt
  • client-go/hack/boilerplate_overlay.go.txt
  • client-go/hack/overlays/client/versioned/clientset.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go
  • client-go/nvgrpc/client_conn.go
  • client-go/nvgrpc/client_conn_test.go
  • client-go/nvgrpc/config.go
  • client-go/nvgrpc/config_test.go
  • client-go/nvgrpc/interceptors.go
  • client-go/nvgrpc/interceptors_test.go
  • client-go/nvgrpc/options.go
  • client-go/nvgrpc/options_test.go
  • client-go/nvgrpc/watcher.go
  • client-go/nvgrpc/watcher_test.go
  • client-go/version/version.go
  • client-go/version/version_test.go
✅ Files skipped from review due to trivial changes (2)
  • client-go/hack/boilerplate_overlay.go.txt
  • api/hack/boilerplate.go.txt
🚧 Files skipped from review as they are similar to previous changes (26)
  • client-go/hack/boilerplate.go.txt
  • client-go/examples/README.md
  • client-go/nvgrpc/client_conn.go
  • client-go/nvgrpc/interceptors_test.go
  • client-go/version/version_test.go
  • client-go/nvgrpc/client_conn_test.go
  • client-go/examples/streaming-daemon/main.go
  • api/device/v1alpha1/gpu_conversion_test.go
  • api/device/v1alpha1/register.go
  • client-go/go.mod
  • client-go/examples/basic-client/main.go
  • client-go/hack/overlays/client/versioned/clientset.go
  • Makefile
  • api/device/v1alpha1/gpu_conversion.go
  • client-go/nvgrpc/interceptors.go
  • client-go/nvgrpc/config.go
  • api/device/v1alpha1/gpu_types.go
  • api/go.mod
  • client-go/nvgrpc/options.go
  • .coderabbit.yaml
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go
  • client-go/nvgrpc/watcher.go
  • client-go/nvgrpc/config_test.go
  • client-go/examples/fake-server/README.md
  • client-go/examples/streaming-daemon/README.md
  • client-go/hack/apply-overlays.sh
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.go: Follow standard Go conventions with gofmt and golint
Use structured logging via log/slog in Go code
Wrap errors with context using fmt.Errorf("context: %w", err) in Go code
Within retry.RetryOnConflict blocks, return errors without wrapping to preserve retry behavior
Use meaningful variable names such as synced over ok for cache sync checks
Use client-go for Kubernetes API interactions in Go code
Prefer informers over direct API calls for watching Kubernetes resources
Implement proper shutdown handling with context cancellation in Go code
Package-level godoc required for all Go packages
Function comments required for all exported Go functions
Use inline comments for complex logic only in Go code
TODO comments should reference issues in Go code
Extract informer event handler setup into helper methods
Use separate informers for different Kubernetes resource types

Files:

  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • api/device/v1alpha1/converter.go
  • api/device/v1alpha1/doc.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/examples/fake-server/main.go
  • client-go/examples/controller-shim/main.go
  • client-go/nvgrpc/options_test.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/version/version.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go
  • client-go/nvgrpc/watcher_test.go
**/*_test.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*_test.go: Use envtest for testing Kubernetes controllers instead of fake clients
Use testify/assert and testify/require for assertions in Go tests
Write table-driven tests when testing multiple scenarios in Go
Name Go tests descriptively using format: TestFunctionName_Scenario_ExpectedBehavior

Files:

  • client-go/nvgrpc/options_test.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/nvgrpc/watcher_test.go
🧠 Learnings (19)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code

Applied to files:

  • .gitignore
  • client-go/README.md
  • .gitattributes
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/examples/basic-client/README.md
  • .versions.yaml
  • client-go/version/version.go
  • client-go/Makefile
  • client-go/DEVELOPMENT.md
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Follow standard Go conventions with gofmt and golint

Applied to files:

  • .gitignore
  • .gitattributes
  • .versions.yaml
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Use `envtest` for testing Kubernetes controllers instead of fake clients

Applied to files:

  • .gitignore
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • .versions.yaml
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/nvgrpc/watcher_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Function comments required for all exported Go functions

Applied to files:

  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/examples/fake-server/main.go
  • client-go/examples/controller-shim/main.go
  • client-go/version/version.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Package-level godoc required for all Go packages

Applied to files:

  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/examples/fake-server/main.go
  • client-go/examples/controller-shim/main.go
  • client-go/version/version.go
📚 Learning: 2025-11-04T06:31:02.147Z
Learnt from: Gyan172004
Repo: NVIDIA/NVSentinel PR: 223
File: platform-connectors/pkg/nodemetadata/processor.go:0-0
Timestamp: 2025-11-04T06:31:02.147Z
Learning: In platform-connectors/pkg/nodemetadata/processor.go, the NewProcessor function does not perform a nil check on the config parameter because the caller is expected to guarantee a non-nil config is provided.

Applied to files:

  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Prefer informers over direct API calls for watching Kubernetes resources

Applied to files:

  • client-go/examples/controller-shim/main.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/nvgrpc/watcher_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use separate informers for different Kubernetes resource types

Applied to files:

  • client-go/examples/controller-shim/main.go
  • client-go/hack/overlays/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use meaningful variable names such as `synced` over `ok` for cache sync checks

Applied to files:

  • client-go/examples/controller-shim/main.go
  • client-go/hack/overlays/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Keep Go dependencies minimal and up-to-date

Applied to files:

  • .versions.yaml
  • api/Makefile
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to data-models/protobufs/**/*.proto : Include comprehensive comments for all fields in Protocol Buffer messages

Applied to files:

  • api/proto/device/v1alpha1/gpu.proto
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to data-models/protobufs/**/*.proto : Use semantic versioning for breaking changes in Protocol Buffer messages

Applied to files:

  • api/proto/device/v1alpha1/gpu.proto
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Implement proper shutdown handling with context cancellation in Go code

Applied to files:

  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/nvgrpc/watcher_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : TODO comments should reference issues in Go code

Applied to files:

  • client-go/version/version.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Use `testify/assert` and `testify/require` for assertions in Go tests

Applied to files:

  • client-go/nvgrpc/watcher_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Write table-driven tests when testing multiple scenarios in Go

Applied to files:

  • client-go/nvgrpc/watcher_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Name Go tests descriptively using format: `TestFunctionName_Scenario_ExpectedBehavior`

Applied to files:

  • client-go/nvgrpc/watcher_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Aim for >80% test coverage on critical paths in Go code

Applied to files:

  • client-go/nvgrpc/watcher_test.go
🧬 Code graph analysis (6)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (1)
  • GPUInterface (22-27)
client-go/examples/fake-server/main.go (3)
client-go/nvgrpc/config.go (2)
  • NvidiaDeviceAPITargetEnvVar (28-28)
  • DefaultNvidiaDeviceAPISocket (31-31)
api/device/v1alpha1/gpu_types.go (3)
  • GPU (55-61)
  • GPUSpec (24-30)
  • GPUStatus (35-45)
api/device/v1alpha1/gpu_conversion.go (1)
  • ToProto (35-40)
client-go/nvgrpc/options_test.go (1)
client-go/nvgrpc/options.go (4)
  • DialOption (23-23)
  • WithLogger (32-36)
  • WithUnaryInterceptor (39-43)
  • WithStreamInterceptor (46-50)
client-go/hack/overlays/client/versioned/integration_test.go (7)
commons/pkg/server/server.go (1)
  • NewServer (375-396)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/hack/overlays/client/versioned/clientset.go (2)
  • NewForConfigAndClient (48-65)
  • New (79-83)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (2)
  • NewForConfigAndClient (39-44)
  • New (58-63)
api/device/v1alpha1/gpu_types.go (1)
  • GPU (55-61)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
node-drainer/pkg/config/config.go (1)
  • Duration (37-39)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (5)
api/device/v1alpha1/gpu_types.go (2)
  • GPU (55-61)
  • GPUList (67-71)
client-go/hack/overlays/client/versioned/clientset.go (1)
  • Interface (12-14)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1)
  • DeviceV1alpha1Client (15-18)
api/device/v1alpha1/gpu_conversion.go (2)
  • FromProto (25-32)
  • FromProtoList (43-48)
client-go/nvgrpc/watcher.go (1)
  • NewWatcher (49-64)
client-go/nvgrpc/watcher_test.go (1)
client-go/nvgrpc/watcher.go (1)
  • NewWatcher (49-64)
🪛 checkmake (0.2.2)
client-go/Makefile

[warning] 187-187: Target "tools" should be declared PHONY.

(phonydeclared)

🪛 LanguageTool
client-go/DEVELOPMENT.md

[style] ~77-~77: This phrase is redundant. Consider using “inside”.
Context: ... informers/) The directory structure inside of hack/overlays/ *must exactly mirror...

(OUTSIDE_OF)

🪛 markdownlint-cli2 (0.18.1)
client-go/DEVELOPMENT.md

10-10: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


11-11: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)

🔇 Additional comments (52)
.gitignore (1)

18-18: ✓ Appropriate addition to support code generation outputs.

The addition of client-go/bin/* mirrors the existing api/bin/* rule and correctly excludes generated binaries from the client-go code-gen workflow, keeping version control clean.

client-go/version/version.go (1)

22-35: LGTM! Clean version stamping implementation.

The implementation correctly provides build-time version information and user-agent string generation. The GitVersion variable is properly set up for ldflags injection, and the UserAgent function correctly formats the string with version and platform information.

client-go/examples/controller-shim/README.md (3)

34-34: Unix socket path syntax is correct.

The syntax unix:///tmp/device-api.sock follows gRPC's RFC 3986 URI syntax where the path must be absolute and the last of the three slashes is actually part of the path. This is the standard format for Go gRPC UDS connections.


37-37: No action needed. The Fake Server's README already clearly documents the NVIDIA_DEVICE_API_TARGET environment variable, its default value (/var/run/nvidia-device-api/device-api.sock), and when it must be exported. The controller-shim README's reference to this variable is well-supported by existing documentation.


54-54: Verify main.go exists with NewInformer implementation.

The implementation note directs users to review NewInformer setup in main.go. This file exists in the same directory and contains a clear example of the gRPC/UDS informer injection pattern.

client-go/nvgrpc/watcher_test.go (3)

179-190: LGTM! Minimal and correct runtime.Object implementation.

FakeObject correctly implements the runtime.Object interface for testing. The DeepCopyObject method provides an adequate copy since both TypeMeta and Name are value types.


192-195: LGTM! Simple and appropriate test data structure.

The testEvent struct cleanly represents event type and object pairs for test scenarios.


197-239: LGTM! Well-implemented test source with correct defensive programming.

FakeSource correctly implements the nvgrpc.Source interface:

  • Next() appropriately prioritizes queued errors before events and returns io.EOF when exhausted
  • Close() safely handles multiple close calls with a select guard (lines 233-237)
  • The nil check on line 230 is defensive programming that protects against direct struct initialization bypassing NewFakeSource()

The implementation provides a clean, reusable test utility for validating Watcher behavior.

client-go/examples/controller-shim/main.go (4)

15-20: Package documentation is clear and well-structured.

The package-level godoc effectively explains the controller-shim pattern and its integration with gRPC-backed informers.


71-112: Manager setup and cache customization are well-implemented.

The custom NewInformer hook correctly injects the gRPC-backed informer for GPU objects and falls back to a standard informer for other types. The indexer merging logic (lines 90-98) properly avoids conflicts by checking existing indexers before adding new ones.


45-63: Setup and initialization logic is well-structured.

The logger setup, target determination from environment variables, and clientset initialization are all correctly implemented with appropriate error handling.


114-127: Reconciler registration and manager startup are correctly implemented.

The reconciler is properly registered with the manager, and shutdown handling uses ctrl.SetupSignalHandler() for proper context cancellation.

client-go/examples/basic-client/README.md (1)

1-18: LGTM!

Clear documentation covering client initialization, K8s-native verbs, and metadata inspection. The fake-server path is now correct at ../fake-server.

.gitattributes (1)

1-16: LGTM!

Properly configured to hide generated code from GitHub PR diffs. The patterns correctly cover Kubernetes-generated helpers (zz_generated.*.go), protobuf bindings (*.pb.go), and the generated client library paths.

api/device/v1alpha1/doc.go (1)

1-19: LGTM!

The package documentation follows Go conventions and includes the required +groupName annotation for Kubernetes code generators. The package-level godoc clearly describes the API schema definitions. As per coding guidelines, package-level documentation is required for all Go packages—this requirement is satisfied.

client-go/README.md (1)

1-96: LGTM!

Comprehensive and well-structured documentation covering:

  • Clear experimental preview warning
  • Kubernetes-native features (clientsets, informers, listers)
  • Practical Quick Start example with idiomatic Go patterns
  • Detailed deployment guidance for DaemonSets including volume mounts and security considerations
  • Consistent socket path references throughout

The documentation effectively onboards users to the SDK. As per coding guidelines, using client-go for Kubernetes API interactions is the recommended approach, and this SDK follows that pattern.

api/proto/device/v1alpha1/gpu.proto (2)

27-77: Well-designed metadata structure aligned with Kubernetes conventions.

The new ObjectMeta and ListMeta messages properly subset the Kubernetes API machinery types, enabling resource_version support for Watch semantics and optimistic concurrency. Field documentation is comprehensive as required by coding guidelines for Protocol Buffer messages.


152-167: LGTM!

Adding resource_version to ListGpusRequest and WatchGpusRequest enables clients to list resources at a specific version and start watches from a consistent point, which is essential for proper cache synchronization.

api/device/v1alpha1/converter.go (2)

23-104: Well-structured goverter interface with comprehensive field mappings.

The Converter interface is cleanly annotated with goverter directives, properly ignoring protobuf internal fields (state, sizeCache, unknownFields) and Kubernetes-specific fields not present in the protobuf definitions. The field mappings between Uuid/UUID and metadata structures are correctly specified.


106-120: TypeMeta helpers now correctly return full APIVersion.

The fix to use SchemeGroupVersion.String() instead of .Version ensures APIVersion is properly formatted as device.nvidia.com/v1alpha1.

.versions.yaml (1)

49-50: Version additions are consistent with project dependencies.

The goverter: 'v1.9.2' and kubernetes_code_gen: 'v0.34.1' entries align with the code generation workflow and match the k8s.io/client-go version used in the project.

client-go/DEVELOPMENT.md (1)

48-70: Excellent documentation of the code generation pipeline.

The mermaid diagram clearly illustrates the flow from API definitions through the generators to the final SDK. The explanation of each component (client-gen, lister-gen, informer-gen, overlays) is concise and informative.

client-go/hack/overlays/client/versioned/integration_test.go (3)

33-62: Well-structured test setup with bufconn for in-process gRPC testing.

The test correctly sets up an in-memory gRPC server using bufconn, creates a mock GPU service, and establishes a clientset connection. The context timeout and proper cleanup with defer statements are appropriate.


256-276: Mock server implementation is clean and thread-safe.

The mockGpuServer correctly uses sync.RWMutex for concurrent access protection, maintains in-memory GPU state, and provides a channel-based mechanism for injecting watch events during tests.


298-332: WatchGpus correctly implements initial snapshot followed by live updates.

The implementation properly sends the initial state as ADDED events under a read lock, then streams live events from the channel until the context is cancelled.

client-go/examples/fake-server/main.go (3)

15-20: Good package-level documentation.

The package documentation clearly explains the purpose of this fake server for local testing and development.


135-169: Simulation logic is well-implemented.

The simulateChanges function correctly uses a ticker for periodic updates, properly locks when modifying state, increments ResourceVersion for watch semantics, and broadcasts updates to all connected watchers.


171-180: Non-blocking broadcast prevents slow consumers from blocking the simulator.

The default case in the select statement ensures that slow or stuck watch streams don't block the simulation loop. This is a good resilience pattern for a fake server.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (7)

9-12: LGTM: Clean interface design.

The interface follows standard Kubernetes client-go patterns by exposing the gRPC connection and resource-specific getters.


14-18: LGTM: Well-structured client.

The client struct appropriately encapsulates the gRPC connection and logger with private fields.


20-22: LGTM: Standard accessor pattern.

The GPUs() method correctly delegates to the newGPUs constructor following client-go conventions.


24-35: LGTM: Safe config handling with shallow copy.

The constructor correctly creates a shallow copy of the config to prevent mutation and properly handles errors from the connection creation.


46-55: LGTM: Standard OrDie pattern.

The constructor correctly implements the Kubernetes-style "OrDie" pattern for initialization-time configuration.


57-63: LGTM: Appropriate fallback constructor.

The New constructor correctly handles the case where a connection is provided directly, using a discarded logger as a sensible default.


65-73: LGTM: Proper nil-safety.

The ClientConn accessor correctly handles the nil receiver case, preventing panics when called on a nil client pointer.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (5)

15-19: LGTM: Standard getter interface.

The GPUsGetter interface follows Kubernetes client-go conventions for resource-specific getters.


29-33: LGTM: Clean struct design.

The gpus struct appropriately encapsulates the gRPC service client and logger.


43-56: LGTM: Correct Get implementation.

The method properly handles the gRPC call, converts the protobuf response to internal types, and logs at an appropriate verbosity level.


58-71: LGTM: Proper List implementation.

The method correctly passes the ResourceVersion from ListOptions, converts the response, and logs useful metadata.


73-87: LGTM: Robust Watch implementation.

The method properly handles context cancellation, error cleanup, and integrates with the nvgrpc watcher pattern. The use of ResourceVersion from ListOptions ensures correct watch semantics.

api/Makefile (6)

19-60: LGTM: Well-structured configuration.

The configuration section properly defines all necessary variables including API_PKGS_COMMA (which was flagged in a previous review but is now correctly defined on line 37). The GO_VERSION extraction with fallback is a good practice.


62-79: LGTM: Clean tooling setup.

The tool configuration properly uses yq to centralize version management and includes a helpful error message if yq is not installed.


86-109: LGTM: Proper target dependencies.

The target chain correctly ensures code generation runs before build and test, and appropriately excludes generated code from test coverage.


112-141: LGTM: Robust code generation workflow.

The generation targets properly handle per-version code generation with appropriate clean dependencies and correct use of API_PKGS_COMMA.


143-167: LGTM: Comprehensive cleanup targets.

The hierarchical clean targets (clean vs purge) provide appropriate granularity for cleanup operations.


171-205: LGTM: Solid tool installation pattern.

The go-install-tool macro correctly handles versioned tool binaries with symlinks and ensures the correct Go toolchain is used for installation.

client-go/Makefile (6)

19-67: LGTM: Comprehensive configuration.

The configuration properly sets up module paths, API versions, build flags for version embedding, and Go version detection with appropriate fallback.


69-83: LGTM: Consistent tool versioning.

The tool configuration follows the same yq-based version management pattern as the api/Makefile, promoting consistency across the codebase.


89-113: LGTM: Well-organized build workflow.

The targets properly chain dependencies and appropriately exclude generated code and examples from testing while including version flags in the build.


115-149: LGTM: Standard Kubernetes code generation.

The client-gen, lister-gen, and informer-gen targets follow standard Kubernetes patterns with appropriate flags and output configuration. The copy-overlays step ensures custom code is properly applied after generation.


151-176: LGTM: Comprehensive cleanup.

The clean targets provide appropriate granularity with separate targets for each generated component and a purge option for complete cleanup.


180-213: LGTM: Consistent tool installation.

The install-tools targets and go-install-tool macro follow the same robust pattern as the api/Makefile, ensuring consistent tool management across modules.

Copy link
Contributor

@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: 4

♻️ Duplicate comments (8)
client-go/nvgrpc/watcher_test.go (1)

154-177: Critical: Race condition due to time.Sleep in test.

Line 160 uses time.Sleep(10 * time.Millisecond) to "allow the receive loop to start," creating a race condition. There's no guarantee the goroutine has started or reached the desired state, making this test flaky on slower systems or under load.

🔎 Recommended fix: Remove sleep and rely on observable behavior

Remove the sleep entirely and rely on the observable effects of Stop():

 func TestWatcher_Stop(t *testing.T) {
 	ctx, cancel := context.WithCancel(context.Background())
 	source := NewFakeSource()
 
 	w := NewWatcher(source, cancel, logr.Discard())
-	// Allow the receive loop to start
-	time.Sleep(10 * time.Millisecond)
 	w.Stop()
 
 	select {
 	case <-ctx.Done():
 	case <-time.After(time.Second):
 		t.Error("context not cancelled after Stop()")
 	}
 
 	select {
 	case _, ok := <-w.ResultChan():
 		if ok {
 			t.Error("ResultChan not closed")
 		}
 	case <-time.After(time.Second):
 		t.Error("ResultChan hang")
 	}
 }

The timeouts in the select statements provide sufficient protection against hangs while verifying that Stop() cancels the context and closes ResultChan.

api/proto/device/v1alpha1/gpu.proto (1)

27-51: Inconsistent indentation in proto comments.

Lines 35-37 within the ObjectMeta comment block use tabs for indentation, while the surrounding comment lines use spaces. This inconsistency should be normalized to use spaces throughout for better readability and consistency with protobuf style conventions.

🔎 Proposed fix
   // resource_version represents the internal version of this object.
   //
   // Value must be treated as opaque by clients and passed unmodified back to the server.
-	// Populated by the system.
-	// Read-only.
-	// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
+  // Populated by the system.
+  // Read-only.
+  // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
   string resource_version = 2;
client-go/examples/basic-client/README.md (1)

20-38: Socket path mismatch between instructions and expected output.

Line 24 instructs users to set NVIDIA_DEVICE_API_TARGET=unix:///tmp/device-api.sock, but the expected output at line 31 displays unix:///tmp/nvidia-device-api.sock. These paths must match for the example to be accurate.

🔎 Proposed fix
-"level"=0 "msg"="discovered GPUs" "count"=8 "target"="unix:///tmp/nvidia-device-api.sock"
+"level"=0 "msg"="discovered GPUs" "count"=8 "target"="unix:///tmp/device-api.sock"
client-go/hack/overlays/client/versioned/integration_test.go (1)

209-213: Unsafe call to t.Errorf from a goroutine.

Calling t.Errorf (or any t method) from a goroutine is unsafe and can cause race conditions. The testing package is not designed for concurrent access to *testing.T.

🔎 Proposed fix using an error channel
+		errCh := make(chan error, 1)
 		go func() {
 			if err := c.Start(ctx); err != nil {
-				t.Errorf("Cache failed to start: %v", err)
+				errCh <- err
 			}
+			close(errCh)
 		}()
 
 		if !c.WaitForCacheSync(ctx) {
 			t.Fatal("Controller-runtime cache failed to sync")
 		}
+
+		// Check for startup errors after sync
+		select {
+		case err := <-errCh:
+			if err != nil {
+				t.Fatalf("Cache failed to start: %v", err)
+			}
+		default:
+		}
client-go/examples/streaming-daemon/main.go (1)

146-148: Misleading log message.

The log message says "context timeout reached" but the context is created from signal.NotifyContext (line 93), which cancels on signals (SIGINT/SIGTERM), not on timeout.

🔎 Proposed fix
 			case <-ctx.Done():
-				logger.Info("context timeout reached, stopping watch")
+				logger.Info("received shutdown signal, stopping watch")
 				return
client-go/Makefile (1)

187-187: Declare the tools target as PHONY.

The tools target should be declared .PHONY since it doesn't produce a file output and is used as a convenience alias for tool binaries.

Proposed fix
+.PHONY: tools
 tools: $(CLIENT_GEN) $(LISTER_GEN) $(INFORMER_GEN)
client-go/examples/controller-shim/main.go (2)

65-69: The informer factory is never started.

The comment on line 67 states the Manager will start the injected informer, but controller-runtime only starts informers created through its own cache machinery. The gRPC-backed informer from factory needs to be started explicitly; otherwise, the cache will never populate and reconciliation won't occur.

Suggested fix
 	factory := informers.NewSharedInformerFactory(clientset, 10*time.Minute)
 	gpuInformer := factory.Device().V1alpha1().GPUs().Informer()

+	// Start the factory in the background before the manager attempts to use the cache.
+	stopCh := make(chan struct{})
+	defer close(stopCh)
+	factory.Start(stopCh)

135-152: Add godoc comments for exported methods.

The exported methods Reconcile and SetupWithManager lack documentation. As per coding guidelines, function comments are required for all exported Go functions.

Suggested additions
+// Reconcile retrieves the requested GPU resource from the gRPC-backed cache
+// and logs its name and UUID. It returns without error if the GPU is not found.
 func (r *GPUReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
 	log := ctrl.LoggerFrom(ctx)

 	var gpu devicev1alpha1.GPU
 	// The Get call is transparently routed through the injected gRPC-backed informer.
 	if err := r.Get(ctx, req.NamespacedName, &gpu); err != nil {
 		return ctrl.Result{}, client.IgnoreNotFound(err)
 	}

 	log.Info("Reconciled GPU", "name", gpu.Name, "uuid", gpu.Spec.UUID)
 	return ctrl.Result{}, nil
 }

+// SetupWithManager registers this reconciler with the provided manager,
+// configuring it to watch GPU resources.
 func (r *GPUReconciler) SetupWithManager(mgr ctrl.Manager) error {
🧹 Nitpick comments (5)
client-go/nvgrpc/watcher_test.go (2)

179-190: Consider adding godoc for exported test utility.

FakeObject is an exported type but lacks a doc comment. While test utilities have lower documentation requirements, adding a brief comment would improve clarity for developers using this in other tests.

As per coding guidelines, exported functions should have doc comments.

🔎 Suggested doc comment
+// FakeObject is a minimal implementation of runtime.Object for testing.
+// It contains only a TypeMeta and Name field.
 type FakeObject struct {
 	metav1.TypeMeta
 	Name string
 }

197-239: Consider adding godoc for exported test utilities.

FakeSource and NewFakeSource are exported but lack doc comments. Adding brief documentation would help developers understand their purpose and usage in tests.

As per coding guidelines, exported functions should have doc comments.

🔎 Suggested doc comments
+// FakeSource implements nvgrpc.Source for testing.
+// It allows tests to inject predetermined events and errors to verify Watcher behavior.
 type FakeSource struct {
 	events chan testEvent
 	errs   []error
 	done   chan struct{}
 }
 
+// NewFakeSource creates a new FakeSource with initialized channels.
 func NewFakeSource() *FakeSource {
 	return &FakeSource{
 		events: make(chan testEvent, 10),
 		done:   make(chan struct{}),
 	}
 }
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (2)

9-12: Add godoc for exported interface.

The DeviceV1alpha1Interface is exported but lacks documentation. As per coding guidelines, function comments are required for all exported Go functions (interfaces included).

Suggested addition
+// DeviceV1alpha1Interface provides access to resources in the device.nvidia.com/v1alpha1 API group.
 type DeviceV1alpha1Interface interface {
 	ClientConn() grpc.ClientConnInterface
 	GPUsGetter
 }

37-44: Consider validating config in NewForConfigAndClient.

While NewForConfig validates through nvgrpc.ClientConnFor, direct callers of NewForConfigAndClient bypass validation. Consider adding a nil check or validation call for defensive programming.

Proposed validation addition
 func NewForConfigAndClient(c *nvgrpc.Config, conn grpc.ClientConnInterface) (*DeviceV1alpha1Client, error) {
+	if c == nil {
+		return nil, fmt.Errorf("config cannot be nil")
+	}
 	return &DeviceV1alpha1Client{
 		conn:   conn,
 		logger: c.GetLogger().WithName("device.v1alpha1"),
 	}, nil
 }
api/Makefile (1)

36-37: Minor formatting: missing space after # in comment.

Line 36 has #Helper instead of # Helper for consistency with other comments.

Proposed fix
-#Helper for tools that need comma-separated package paths
+# Helper for tools that need comma-separated package paths
 API_PKGS_COMMA := $(subst $(SPACE),$(COMMA),$(API_PKGS))
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a1fae68 and 346284e.

⛔ Files ignored due to path filters (28)
  • api/device/v1alpha1/zz_generated.conversion.go is excluded by !api/**/zz_generated.*
  • api/device/v1alpha1/zz_generated.deepcopy.go is excluded by !api/**/zz_generated.*
  • api/gen/go/device/v1alpha1/gpu.pb.go is excluded by !**/*.pb.go, !**/gen/**, !api/gen/**
  • api/go.sum is excluded by !**/*.sum
  • client-go/client/versioned/clientset.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/clientset_generated.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/register.go is excluded by !client-go/client/**
  • client-go/client/versioned/integration_test.go is excluded by !client-go/client/**
  • client-go/client/versioned/scheme/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/scheme/register.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/device_client.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_gpu.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/generated_expansion.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/gpu.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go is excluded by !client-go/client/**
  • client-go/go.sum is excluded by !**/*.sum
  • client-go/informers/externalversions/device/interface.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/device/v1alpha1/gpu.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/device/v1alpha1/interface.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/factory.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/generic.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go is excluded by !client-go/informers/**
  • client-go/listers/device/v1alpha1/expansion_generated.go is excluded by !client-go/listers/**
  • client-go/listers/device/v1alpha1/gpu.go is excluded by !client-go/listers/**
📒 Files selected for processing (49)
  • .coderabbit.yaml
  • .gitattributes
  • .gitignore
  • .versions.yaml
  • Makefile
  • api/Makefile
  • api/device/v1alpha1/converter.go
  • api/device/v1alpha1/doc.go
  • api/device/v1alpha1/gpu_conversion.go
  • api/device/v1alpha1/gpu_conversion_test.go
  • api/device/v1alpha1/gpu_types.go
  • api/device/v1alpha1/register.go
  • api/go.mod
  • api/hack/boilerplate.go.txt
  • api/proto/device/v1alpha1/gpu.proto
  • client-go/DEVELOPMENT.md
  • client-go/Makefile
  • client-go/README.md
  • client-go/examples/README.md
  • client-go/examples/basic-client/README.md
  • client-go/examples/basic-client/main.go
  • client-go/examples/controller-shim/README.md
  • client-go/examples/controller-shim/main.go
  • client-go/examples/fake-server/README.md
  • client-go/examples/fake-server/main.go
  • client-go/examples/streaming-daemon/README.md
  • client-go/examples/streaming-daemon/main.go
  • client-go/go.mod
  • client-go/hack/apply-overlays.sh
  • client-go/hack/boilerplate.go.txt
  • client-go/hack/boilerplate_overlay.go.txt
  • client-go/hack/overlays/client/versioned/clientset.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go
  • client-go/nvgrpc/client_conn.go
  • client-go/nvgrpc/client_conn_test.go
  • client-go/nvgrpc/config.go
  • client-go/nvgrpc/config_test.go
  • client-go/nvgrpc/interceptors.go
  • client-go/nvgrpc/interceptors_test.go
  • client-go/nvgrpc/options.go
  • client-go/nvgrpc/options_test.go
  • client-go/nvgrpc/watcher.go
  • client-go/nvgrpc/watcher_test.go
  • client-go/version/version.go
  • client-go/version/version_test.go
✅ Files skipped from review due to trivial changes (2)
  • api/hack/boilerplate.go.txt
  • .gitattributes
🚧 Files skipped from review as they are similar to previous changes (23)
  • .versions.yaml
  • client-go/version/version_test.go
  • .coderabbit.yaml
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/nvgrpc/interceptors_test.go
  • api/device/v1alpha1/doc.go
  • client-go/nvgrpc/interceptors.go
  • client-go/examples/controller-shim/README.md
  • client-go/hack/boilerplate.go.txt
  • client-go/hack/overlays/client/versioned/clientset.go
  • client-go/nvgrpc/client_conn_test.go
  • client-go/examples/fake-server/README.md
  • client-go/hack/apply-overlays.sh
  • client-go/nvgrpc/client_conn.go
  • client-go/examples/fake-server/main.go
  • api/device/v1alpha1/gpu_types.go
  • client-go/nvgrpc/watcher.go
  • client-go/examples/basic-client/main.go
  • client-go/version/version.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go
  • client-go/examples/streaming-daemon/README.md
  • .gitignore
  • client-go/nvgrpc/options_test.go
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.go: Follow standard Go conventions with gofmt and golint
Use structured logging via log/slog in Go code
Wrap errors with context using fmt.Errorf("context: %w", err) in Go code
Within retry.RetryOnConflict blocks, return errors without wrapping to preserve retry behavior
Use meaningful variable names such as synced over ok for cache sync checks
Use client-go for Kubernetes API interactions in Go code
Prefer informers over direct API calls for watching Kubernetes resources
Implement proper shutdown handling with context cancellation in Go code
Package-level godoc required for all Go packages
Function comments required for all exported Go functions
Use inline comments for complex logic only in Go code
TODO comments should reference issues in Go code
Extract informer event handler setup into helper methods
Use separate informers for different Kubernetes resource types

Files:

  • api/device/v1alpha1/gpu_conversion_test.go
  • api/device/v1alpha1/gpu_conversion.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/examples/streaming-daemon/main.go
  • client-go/nvgrpc/config.go
  • client-go/examples/controller-shim/main.go
  • client-go/nvgrpc/watcher_test.go
  • api/device/v1alpha1/register.go
  • client-go/nvgrpc/config_test.go
  • api/device/v1alpha1/converter.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/nvgrpc/options.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go
**/*_test.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*_test.go: Use envtest for testing Kubernetes controllers instead of fake clients
Use testify/assert and testify/require for assertions in Go tests
Write table-driven tests when testing multiple scenarios in Go
Name Go tests descriptively using format: TestFunctionName_Scenario_ExpectedBehavior

Files:

  • api/device/v1alpha1/gpu_conversion_test.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/nvgrpc/watcher_test.go
  • client-go/nvgrpc/config_test.go
**/go.mod

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use go.mod for each service as a separate Go module with semantic import versioning

Files:

  • api/go.mod
  • client-go/go.mod
🧠 Learnings (24)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code

Applied to files:

  • client-go/examples/basic-client/README.md
  • client-go/examples/README.md
  • client-go/DEVELOPMENT.md
  • api/go.mod
  • client-go/README.md
  • client-go/go.mod
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/hack/boilerplate_overlay.go.txt
  • client-go/Makefile
📚 Learning: 2025-12-22T16:16:24.320Z
Learnt from: pteranodan
Repo: NVIDIA/NVSentinel PR: 607
File: client-go/nvgrpc/config_test.go:61-80
Timestamp: 2025-12-22T16:16:24.320Z
Learning: In Go tests across the repository, avoid introducing the testify dependency for simple equality/inequality checks. Use the standard testing package assertions (t.Error, t.Errorf, t.Fatal, etc.) for straightforward checks. Reserve third-party assertion libraries for complex scenarios that require richer diagnostics or expressive matchers.

Applied to files:

  • api/device/v1alpha1/gpu_conversion_test.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/nvgrpc/watcher_test.go
  • client-go/nvgrpc/config_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Use `envtest` for testing Kubernetes controllers instead of fake clients

Applied to files:

  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/examples/README.md
  • client-go/go.mod
  • client-go/nvgrpc/watcher_test.go
  • client-go/nvgrpc/config_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use meaningful variable names such as `synced` over `ok` for cache sync checks

Applied to files:

  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/examples/controller-shim/main.go
  • Makefile
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Implement proper shutdown handling with context cancellation in Go code

Applied to files:

  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/examples/streaming-daemon/main.go
  • client-go/nvgrpc/watcher_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use separate informers for different Kubernetes resource types

Applied to files:

  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/examples/controller-shim/main.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Prefer informers over direct API calls for watching Kubernetes resources

Applied to files:

  • client-go/hack/overlays/client/versioned/integration_test.go
  • api/go.mod
  • client-go/examples/controller-shim/main.go
  • client-go/go.mod
  • client-go/nvgrpc/watcher_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Package-level godoc required for all Go packages

Applied to files:

  • client-go/examples/streaming-daemon/main.go
  • client-go/examples/controller-shim/main.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to data-models/protobufs/**/*.proto : Include comprehensive comments for all fields in Protocol Buffer messages

Applied to files:

  • api/proto/device/v1alpha1/gpu.proto
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to data-models/protobufs/**/*.proto : Use semantic versioning for breaking changes in Protocol Buffer messages

Applied to files:

  • api/proto/device/v1alpha1/gpu.proto
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Keep Go dependencies minimal and up-to-date

Applied to files:

  • api/go.mod
  • client-go/go.mod
  • Makefile
  • api/Makefile
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/go.mod : Use `go.mod` for each service as a separate Go module with semantic import versioning

Applied to files:

  • api/go.mod
  • client-go/go.mod
  • Makefile
📚 Learning: 2025-12-22T16:16:24.320Z
Learnt from: pteranodan
Repo: NVIDIA/NVSentinel PR: 607
File: client-go/nvgrpc/config_test.go:61-80
Timestamp: 2025-12-22T16:16:24.320Z
Learning: In the NVIDIA/NVSentinel repository, prefer not to introduce a dependency on `stretchr/testify` for simple comparison assertions in Go tests. Use standard `testing` package assertions (t.Error, t.Errorf, etc.) for straightforward checks.

Applied to files:

  • api/go.mod
  • client-go/go.mod
📚 Learning: 2025-12-01T17:53:20.067Z
Learnt from: jtschelling
Repo: NVIDIA/NVSentinel PR: 455
File: docs/designs/013-remediation-plugins.md:162-204
Timestamp: 2025-12-01T17:53:20.067Z
Learning: Code examples in design documents (docs/designs/) in the NVSentinel repository are illustrative stubs meant to show intent and architectural concepts, and do not need to be 100% correct or complete implementations (e.g., undefined variables, missing error handling, incomplete struct initialization are acceptable).

Applied to files:

  • api/go.mod
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Function comments required for all exported Go functions

Applied to files:

  • client-go/examples/controller-shim/main.go
  • client-go/nvgrpc/options.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : TODO comments should reference issues in Go code

Applied to files:

  • client-go/go.mod
  • client-go/nvgrpc/options.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Follow standard Go conventions with gofmt and golint

Applied to files:

  • Makefile
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Use `testify/assert` and `testify/require` for assertions in Go tests

Applied to files:

  • client-go/nvgrpc/watcher_test.go
  • client-go/nvgrpc/config_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Write table-driven tests when testing multiple scenarios in Go

Applied to files:

  • client-go/nvgrpc/watcher_test.go
  • client-go/nvgrpc/config_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Name Go tests descriptively using format: `TestFunctionName_Scenario_ExpectedBehavior`

Applied to files:

  • client-go/nvgrpc/watcher_test.go
  • client-go/nvgrpc/config_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Aim for >80% test coverage on critical paths in Go code

Applied to files:

  • client-go/nvgrpc/watcher_test.go
  • client-go/nvgrpc/config_test.go
📚 Learning: 2025-11-04T06:31:02.147Z
Learnt from: Gyan172004
Repo: NVIDIA/NVSentinel PR: 223
File: platform-connectors/pkg/nodemetadata/processor.go:0-0
Timestamp: 2025-11-04T06:31:02.147Z
Learning: In platform-connectors/pkg/nodemetadata/processor.go, the NewProcessor function does not perform a nil check on the config parameter because the caller is expected to guarantee a non-nil config is provided.

Applied to files:

  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: All files must include Apache 2.0 license header

Applied to files:

  • client-go/hack/boilerplate_overlay.go.txt
🧬 Code graph analysis (9)
api/device/v1alpha1/gpu_conversion.go (2)
api/device/v1alpha1/converter.go (1)
  • Converter (30-104)
api/device/v1alpha1/gpu_types.go (2)
  • GPU (55-61)
  • GPUList (67-71)
client-go/hack/overlays/client/versioned/integration_test.go (4)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/hack/overlays/client/versioned/clientset.go (2)
  • NewForConfigAndClient (48-65)
  • New (79-83)
api/device/v1alpha1/gpu_types.go (1)
  • GPU (55-61)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
client-go/nvgrpc/config.go (1)
client-go/version/version.go (1)
  • UserAgent (28-35)
client-go/examples/controller-shim/main.go (3)
client-go/nvgrpc/config.go (2)
  • NvidiaDeviceAPITargetEnvVar (28-28)
  • DefaultNvidiaDeviceAPISocket (31-31)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
api/device/v1alpha1/gpu_types.go (1)
  • GPU (55-61)
client-go/nvgrpc/watcher_test.go (1)
client-go/nvgrpc/watcher.go (1)
  • NewWatcher (49-64)
api/device/v1alpha1/register.go (1)
api/device/v1alpha1/gpu_types.go (2)
  • GPU (55-61)
  • GPUList (67-71)
api/device/v1alpha1/converter.go (2)
api/device/v1alpha1/gpu_types.go (4)
  • GPU (55-61)
  • GPUList (67-71)
  • GPUSpec (24-30)
  • GPUStatus (35-45)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (4)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (2)
  • GPUsGetter (17-19)
  • GPUInterface (22-27)
client-go/hack/overlays/client/versioned/clientset.go (4)
  • NewForConfig (32-44)
  • NewForConfigAndClient (48-65)
  • NewForConfigOrDie (69-76)
  • New (79-83)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/nvgrpc/client_conn.go (1)
  • ClientConnFor (26-72)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (5)
api/device/v1alpha1/gpu_types.go (2)
  • GPU (55-61)
  • GPUList (67-71)
client-go/hack/overlays/client/versioned/clientset.go (1)
  • Interface (12-14)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1)
  • DeviceV1alpha1Client (15-18)
api/device/v1alpha1/gpu_conversion.go (2)
  • FromProto (25-32)
  • FromProtoList (43-48)
client-go/nvgrpc/watcher.go (1)
  • NewWatcher (49-64)
🪛 checkmake (0.2.2)
client-go/Makefile

[warning] 187-187: Target "tools" should be declared PHONY.

(phonydeclared)

🔇 Additional comments (55)
client-go/nvgrpc/watcher_test.go (1)

31-58: Past testify suggestion conflicts with repository learning.

A previous review comment suggested using testify/assert and testify/require for these tests. However, based on learnings from this same PR (pteranodan, 2025-12-22), the repository policy is to avoid introducing testify for simple equality/inequality checks and to use standard testing package assertions instead.

The current implementation using t.Fatalf, t.Errorf, etc., aligns with this learning and should be retained.

Based on learnings, repository prefers standard library assertions for simple checks.

client-go/hack/boilerplate_overlay.go.txt (1)

1-16: LGTM: Proper boilerplate for generated overlays.

The Apache 2.0 license header and generated-file notice are correctly formatted for the overlay code-generation workflow.

client-go/README.md (1)

1-94: Excellent documentation for the client-go SDK.

The README provides comprehensive coverage of installation, usage patterns, deployment considerations, and development workflows. The experimental warning is appropriately prominent, and the examples table clearly guides users to the right integration pattern.

api/go.mod (1)

1-34: Well-structured dependency management.

The module correctly declares k8s.io/apimachinery as a direct dependency (line 16) and maintains a clean separation between direct and indirect requires. The Go version bump to 1.25.5 ensures the latest patch-level fixes are included.

api/device/v1alpha1/register.go (1)

15-44: Idiomatic Kubernetes API registration.

The implementation correctly follows Kubernetes API machinery patterns: proper SchemeGroupVersion setup, Resource helper for GroupResource derivation, and standard SchemeBuilder initialization. The type registration includes both GPU and GPUList with metav1.AddToGroupVersion for complete scheme integration.

Based on coding guidelines, this aligns with the requirement to use client-go for Kubernetes API interactions.

client-go/go.mod (1)

1-74: Dependencies properly configured.

The module structure is well-organized with:

  • Latest Go patch version (1.25.5) for security fixes
  • Consistent Kubernetes module versions (all at v0.34.1)
  • Proper local module replacement using canonical v0.0.0 format
  • Clear separation of direct and indirect dependencies

All previously identified issues have been successfully resolved.

client-go/DEVELOPMENT.md (1)

1-105: Comprehensive development guide.

The documentation effectively covers the complete development workflow including:

  • Clear prerequisite requirements
  • Step-by-step code generation process with helpful tips
  • Well-structured pipeline visualization using Mermaid
  • Proper warnings about not editing generated files directly
  • Detailed overlay pattern explanation

The guide provides developers with all necessary context to understand and contribute to the SDK's code-generation workflow.

api/device/v1alpha1/gpu_conversion_test.go (3)

30-43: LGTM! Nil handling tests are correct.

The nil safety tests correctly verify that conversion helpers return nil for nil inputs, preventing potential nil pointer dereferences.


45-88: LGTM! Round-trip conversion test is well-structured.

The test validates critical conversion behaviors including metadata transformation, ResourceVersion propagation, and uses protocmp for accurate protobuf comparison.


90-153: LGTM! GPUList conversion test has good coverage.

The test validates list-level metadata, nested conditions with timestamps, and optional fields like RecommendedAction, ensuring robust conversion behavior.

client-go/nvgrpc/config_test.go (3)

20-59: LGTM! Target precedence test is well-structured.

The table-driven test correctly validates the precedence order: explicit argument > environment variable > default. Uses standard testing package as per repository preference.


61-80: LGTM! UserAgent tests validate default and custom behavior.

The tests correctly verify that empty UserAgent is populated with a default value, while custom values are preserved.


82-120: LGTM! Validation tests cover required fields.

The table-driven validation tests correctly verify that both Target and UserAgent are required fields, returning errors when either is missing.

client-go/examples/streaming-daemon/main.go (2)

15-20: LGTM! Package documentation is clear and comprehensive.

The package-level godoc effectively explains the example's purpose, demonstrating custom interceptors, persistent watch streams, and gRPC connection lifecycle management.


50-53: LGTM! Correct use of nvgrpc constants.

The code properly uses nvgrpc.NvidiaDeviceAPITargetEnvVar and nvgrpc.DefaultNvidiaDeviceAPISocket, ensuring consistency with the SDK defaults.

api/device/v1alpha1/gpu_conversion.go (2)

15-22: LGTM! Build tag and singleton pattern are appropriate.

The !goverter build tag correctly excludes this file during code generation, and the singleton converter instance provides a clean adapter layer.


24-56: LGTM! Conversion helpers are nil-safe.

All four conversion helpers (FromProto, ToProto, FromProtoList, ToProtoList) correctly check for nil inputs and delegate to the singleton converter, providing a clean public API for GPU conversions.

client-go/nvgrpc/options.go (2)

22-29: LGTM! Functional options pattern correctly implemented.

The DialOption type and internal dialOptions struct provide a clean, extensible configuration mechanism for the gRPC client.


31-50: LGTM! Option functions are well-documented and correct.

All three option functions (WithLogger, WithUnaryInterceptor, WithStreamInterceptor) have proper godoc comments and correctly mutate the dialOptions struct.

client-go/hack/overlays/client/versioned/integration_test.go (6)

33-62: LGTM! Test setup is correct.

The test properly sets up an in-process gRPC server using bufconn, creating a realistic end-to-end testing environment without external dependencies.


64-86: LGTM! Get and List tests validate basic operations.

The tests correctly verify clientset Get and List operations, including metadata like ResourceVersion.


88-129: LGTM! Watch flow test validates streaming behavior.

The test correctly verifies initial snapshot delivery and live event propagation through the watch stream.


131-182: LGTM! Informer sync test validates caching behavior.

The test correctly instantiates the informer before starting the factory and validates cache synchronization with polling for eventual consistency.


194-203: LGTM! NewInformer fallback prevents nil pointer issues.

The fallback to cache.NewSharedIndexInformer for non-GPU objects correctly prevents potential nil pointer dereferences, addressing the previous review concern.


254-336: LGTM! Mock server implementation is thread-safe.

The mock server correctly uses sync.RWMutex for concurrent access, properly handles context cancellation, and provides realistic watch stream behavior with initial snapshots and live events.

client-go/examples/controller-shim/main.go (4)

15-20: LGTM on package documentation.

The package-level godoc clearly explains the purpose of this example: demonstrating a Kubernetes controller using gRPC-backed informers to bypass the standard API server.


45-63: LGTM on clientset initialization.

The setup correctly reads the target from the environment variable with a sensible default, and initializes the gRPC-backed clientset with proper error handling.


71-112: LGTM on Manager configuration with custom cache injection.

The custom MapperProvider and NewInformer implementation correctly inject the gRPC-backed informer for GPU resources while falling back to standard informers for other types. The indexer merging logic properly handles conflicts.


130-133: LGTM on GPUReconciler type definition.

The reconciler embeds client.Client following the controller-runtime pattern.

client-go/nvgrpc/config.go (5)

26-38: LGTM on constant definitions.

The exported constants for environment variable, default socket path, and keepalive settings are well-documented and provide sensible defaults.


40-49: LGTM on Config struct definition.

The struct clearly documents its fields. The unexported logger field with a getter pattern is appropriate.


51-67: LGTM on Default() implementation.

The method correctly applies defaults from environment variables and fallback values, following the expected precedence.


69-80: LGTM on Validate() implementation.

The validation correctly checks for required fields and returns descriptive errors with guidance on fixing the issue.


82-89: LGTM on GetLogger() implementation.

The defensive nil-sink check ensures a usable logger is always returned.

api/device/v1alpha1/converter.go (3)

23-104: LGTM on Converter interface definition.

The interface is well-documented with goverter annotations for automatic code generation. The field mappings and ignores are correctly specified for bidirectional proto ↔ Go type conversions.


106-120: LGTM on TypeMeta helper functions.

The functions correctly use SchemeGroupVersion.String() to produce the full group/version format (e.g., device.nvidia.com/v1alpha1) as required by Kubernetes TypeMeta.APIVersion.


122-133: LGTM on timestamp conversion functions.

FromProtobufTimestamp correctly handles nil input by returning a zero-value metav1.Time. ToProtobufTimestamp delegates to timestamppb.New appropriately.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (3)

14-22: LGTM on DeviceV1alpha1Client struct and GPUs accessor.

The struct and accessor are well-documented and follow the standard client-go patterns.


24-35: LGTM on NewForConfig implementation.

The function creates a shallow copy to avoid mutation and delegates to nvgrpc.ClientConnFor, which internally handles defaulting and validation.


46-73: LGTM on remaining constructor variants and ClientConn accessor.

NewForConfigOrDie, New, and ClientConn follow standard client-go patterns with appropriate panic behavior and nil-safety.

api/Makefile (6)

19-37: LGTM on string manipulation helpers and API configuration.

The variable definitions for comma-separated versions and package paths are correctly implemented. The API_PKGS_COMMA variable is now properly defined.


55-59: LGTM on Go version resolution.

The fallback from toolchain directive to go env GOVERSION ensures compatibility across different Go module configurations.


96-100: LGTM on code-gen target.

The target correctly chains dependencies and runs go mod tidy after generation.


111-125: LGTM on protos-generate target.

The per-version loop correctly generates protobuf bindings with proper plugin paths and output options.


127-141: LGTM on deepcopy-gen and conversion-gen targets.

Both targets correctly use the per-version configuration and properly clean before regenerating.


194-205: LGTM on go-install-tool macro.

The macro correctly handles versioned tool installation with symlinks for version management and uses GOTOOLCHAIN for consistent Go version.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (4)

29-41: LGTM on gpus struct and constructor.

The struct correctly wraps the gRPC client with a logger, and the constructor appropriately derives the logger from the parent client.


43-56: LGTM on Get implementation.

The method correctly calls the gRPC service, converts the response using FromProto, and logs at an appropriate verbosity level.


58-71: LGTM on List implementation.

The method correctly passes ResourceVersion for list consistency and logs the result count.


73-87: LGTM on Watch implementation.

The method correctly creates a cancellable context, handles stream creation errors by calling cancel(), and wraps the stream with nvgrpc.NewWatcher. This follows best practices for watch implementations.

client-go/Makefile (5)

19-47: LGTM on configuration section.

The variable definitions for modules, API versions, version flags, and linker flags are well-structured and follow the same patterns as the api/Makefile.


63-67: LGTM on Go version resolution.

The fallback logic from toolchain directive to go env GOVERSION ensures compatibility.


100-113: LGTM on code-gen, build, and test targets.

The targets correctly chain dependencies and exclude generated/example code from compilation and testing where appropriate.


115-149: LGTM on client-gen, lister-gen, informer-gen, and copy-overlays targets.

The generation targets correctly invoke the respective tools with proper flags and the overlay copying script.


198-213: LGTM on go-install-tool macro.

The macro correctly handles versioned tool installation with symlinks and uses GOTOOLCHAIN for consistent Go version.

Copy link
Contributor

@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

♻️ Duplicate comments (15)
client-go/hack/overlays/client/versioned/integration_test.go (1)

209-213: Unsafe use of t.Errorf from goroutine.

Calling t.Errorf from a goroutine is unsafe and can cause data races or panics if the test completes before the goroutine executes. Since c.Start(ctx) blocks until context cancellation, any error would indicate a real problem that should fail the test.

🔎 Proposed fix using an error channel
+		errCh := make(chan error, 1)
 		go func() {
 			if err := c.Start(ctx); err != nil {
-				t.Errorf("Cache failed to start: %v", err)
+				errCh <- err
 			}
+			close(errCh)
 		}()
 
 		if !c.WaitForCacheSync(ctx) {
 			t.Fatal("Controller-runtime cache failed to sync")
 		}
+
+		// Check for startup errors after sync
+		select {
+		case err := <-errCh:
+			if err != nil {
+				t.Fatalf("Cache failed to start: %v", err)
+			}
+		default:
+		}
client-go/nvgrpc/watcher.go (1)

15-30: Missing required package-level documentation.

Per coding guidelines, all Go packages must have package-level godoc comments. This is especially important for public packages like nvgrpc that provide reusable utilities.

🔎 Proposed fix
+// Package nvgrpc provides utilities for building Kubernetes-style watch interfaces
+// over gRPC streaming connections. It includes connection management, interceptors,
+// and a Watcher implementation that bridges gRPC streams to the standard
+// k8s.io/apimachinery/pkg/watch.Interface.
+
 package nvgrpc

Based on coding guidelines, package-level godoc is required for all Go packages.

client-go/version/version.go (1)

15-15: Add package-level godoc comment.

The coding guidelines require package-level godoc for all Go packages. This comment was raised in a previous review and remains unaddressed.

🔎 Suggested addition
+// Package version provides build-time version information and user-agent
+// string generation for the nvidia-device-api-client.
 package version
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1)

25-27: For server-streaming RPCs, CloseSend() is a no-op.

This was raised in a previous review. For server-streaming RPCs like WatchGpus, the client only receives messages and doesn't send after the initial request. While calling CloseSend() is not harmful (it's effectively a no-op), relying on context cancellation is the idiomatic approach for cleanup.

🔎 Suggested fix
 func (a *gpuStreamAdapter) Close() error {
-	return a.stream.CloseSend()
+	// For server-streaming RPCs, cleanup is handled by context cancellation.
+	// CloseSend() is a no-op since the client doesn't send after the initial request.
+	return nil
 }
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (2)

1-7: Add package-level godoc comment.

This was raised in a previous review and remains unaddressed. As per coding guidelines, package-level godoc is required.

🔎 Suggested documentation
+// Package fake provides fake implementations of the device v1alpha1 client
+// for testing purposes. These fakes use an in-memory ObjectTracker instead
+// of actual gRPC connections.
 package fake

13-15: Add function comment for exported method.

This was raised in a previous review and remains unaddressed. As per coding guidelines, function comments are required for all exported Go functions.

🔎 Suggested documentation
+// GPUs returns a fake GPUInterface for testing GPU operations
+// without requiring an actual gRPC connection.
 func (c *FakeDeviceV1alpha1) GPUs() v1alpha1.GPUInterface {
client-go/examples/streaming-daemon/main.go (1)

146-148: Fix misleading log message.

This was raised in a previous review. The log message says "context timeout reached" but the context is created from signal.NotifyContext (line 93) which cancels on SIGINT/SIGTERM signals, not on timeout.

🔎 Suggested fix
 			case <-ctx.Done():
-				logger.Info("context timeout reached, stopping watch")
+				logger.Info("received shutdown signal, stopping watch")
 				return
api/proto/device/v1alpha1/gpu.proto (1)

27-51: Inconsistent indentation in comment blocks (partial fix).

Lines 35-37 still use tabs while the surrounding lines use spaces. This was raised in a previous review and appears to be partially addressed (lines 47-48 now use spaces correctly).

🔎 Suggested fix for remaining inconsistency
   // resource_version represents the internal version of this object.
   //
   // Value must be treated as opaque by clients and passed unmodified back to the server.
-	// Populated by the system.
-	// Read-only.
-	// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
+  // Populated by the system.
+  // Read-only.
+  // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
   string resource_version = 2;
client-go/examples/controller-shim/main.go (1)

135-152: Add godoc comments for exported methods.

This was raised in a previous review. As per coding guidelines, function comments are required for all exported Go functions.

🔎 Suggested additions
+// Reconcile retrieves the requested GPU resource from the gRPC-backed cache
+// and logs its name and UUID. It returns without error if the GPU is not found.
 func (r *GPUReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
+// SetupWithManager registers this reconciler with the provided manager,
+// configuring it to watch GPU resources.
 func (r *GPUReconciler) SetupWithManager(mgr ctrl.Manager) error {
client-go/examples/fake-server/main.go (1)

195-208: ListMeta is not populated in the response.

This was raised in a previous review. The GpuList response doesn't include metadata.resource_version, which is needed for clients to establish a watch from a consistent point (List-then-Watch pattern).

🔎 Suggested fix
 func (s *fakeServer) ListGpus(ctx context.Context, req *pb.ListGpusRequest) (*pb.ListGpusResponse, error) {
 	s.mu.RLock()
 	defer s.mu.RUnlock()

 	gpuList := &pb.GpuList{
+		Metadata: &pb.ListMeta{
+			ResourceVersion: "1", // Or track a global version
+		},
 		Items: make([]*pb.Gpu, 0, len(s.gpus)),
 	}
api/device/v1alpha1/gpu_types.go (1)

15-15: Package-level documentation still missing.

The package-level godoc required by coding guidelines remains absent. This was flagged in a previous review.

Based on coding guidelines: Package-level godoc required for all Go packages.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1)

1-1: Package-level documentation still missing.

The package-level godoc required by coding guidelines remains absent. This was flagged in a previous review.

Based on coding guidelines: Package-level godoc required for all Go packages.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (2)

1-1: Package-level documentation still missing.

The package-level godoc required by coding guidelines remains absent. This was flagged in a previous review.

Based on coding guidelines: Package-level godoc required for all Go packages.


21-27: GPUExpansion interface is still undefined - code will not compile.

The GPUInterface embeds GPUExpansion (line 26), but this interface is not defined anywhere in the codebase. This is a compilation blocker that was flagged in previous reviews.

🔎 Proposed fix

Create a new file gpu_expansion.go in the same directory:

package v1alpha1

// GPUExpansion allows for extension of GPU interface.
type GPUExpansion interface{}
client-go/Makefile (1)

187-187: Declare tools target as .PHONY.

The tools target should be declared .PHONY since it doesn't produce a file output and is used as a convenience alias for tool binaries.

🔎 Proposed fix
+.PHONY: tools
 tools: $(CLIENT_GEN) $(LISTER_GEN) $(INFORMER_GEN)
🧹 Nitpick comments (3)
api/device/v1alpha1/register.go (2)

15-21: Add package-level godoc comment.

As per coding guidelines, package-level godoc is required for all Go packages.

🔎 Suggested documentation
+// Package v1alpha1 contains API types for the device.nvidia.com/v1alpha1 API group.
+// It provides GPU and GPUList resources for representing NVIDIA GPU devices.
 package v1alpha1

25-27: Add function comment for exported function.

As per coding guidelines, function comments are required for all exported Go functions.

🔎 Suggested documentation
+// Resource returns the schema.GroupResource for the given resource name
+// within the device.nvidia.com API group.
 func Resource(resource string) schema.GroupResource {
client-go/examples/fake-server/main.go (1)

262-268: Consider documenting UUID generation approach.

The generateGPUUUID function uses math/rand which is not cryptographically secure, but this is acceptable for a fake server. Consider adding a brief comment noting this is for testing purposes only.

🔎 Suggested documentation
+// generateGPUUUID creates a pseudo-random UUID for fake GPU resources.
+// Uses math/rand (not crypto-secure) which is acceptable for testing purposes.
 func generateGPUUUID() string {
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 346284e and d97ed84.

⛔ Files ignored due to path filters (28)
  • api/device/v1alpha1/zz_generated.conversion.go is excluded by !api/**/zz_generated.*
  • api/device/v1alpha1/zz_generated.deepcopy.go is excluded by !api/**/zz_generated.*
  • api/gen/go/device/v1alpha1/gpu.pb.go is excluded by !**/*.pb.go, !**/gen/**, !api/gen/**
  • api/go.sum is excluded by !**/*.sum
  • client-go/client/versioned/clientset.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/clientset_generated.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/register.go is excluded by !client-go/client/**
  • client-go/client/versioned/integration_test.go is excluded by !client-go/client/**
  • client-go/client/versioned/scheme/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/scheme/register.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/device_client.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_gpu.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/generated_expansion.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/gpu.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go is excluded by !client-go/client/**
  • client-go/go.sum is excluded by !**/*.sum
  • client-go/informers/externalversions/device/interface.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/device/v1alpha1/gpu.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/device/v1alpha1/interface.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/factory.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/generic.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go is excluded by !client-go/informers/**
  • client-go/listers/device/v1alpha1/expansion_generated.go is excluded by !client-go/listers/**
  • client-go/listers/device/v1alpha1/gpu.go is excluded by !client-go/listers/**
📒 Files selected for processing (49)
  • .coderabbit.yaml
  • .gitattributes
  • .gitignore
  • .versions.yaml
  • Makefile
  • api/Makefile
  • api/device/v1alpha1/converter.go
  • api/device/v1alpha1/doc.go
  • api/device/v1alpha1/gpu_conversion.go
  • api/device/v1alpha1/gpu_conversion_test.go
  • api/device/v1alpha1/gpu_types.go
  • api/device/v1alpha1/register.go
  • api/go.mod
  • api/hack/boilerplate.go.txt
  • api/proto/device/v1alpha1/gpu.proto
  • client-go/DEVELOPMENT.md
  • client-go/Makefile
  • client-go/README.md
  • client-go/examples/README.md
  • client-go/examples/basic-client/README.md
  • client-go/examples/basic-client/main.go
  • client-go/examples/controller-shim/README.md
  • client-go/examples/controller-shim/main.go
  • client-go/examples/fake-server/README.md
  • client-go/examples/fake-server/main.go
  • client-go/examples/streaming-daemon/README.md
  • client-go/examples/streaming-daemon/main.go
  • client-go/go.mod
  • client-go/hack/apply-overlays.sh
  • client-go/hack/boilerplate.go.txt
  • client-go/hack/boilerplate_overlay.go.txt
  • client-go/hack/overlays/client/versioned/clientset.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go
  • client-go/nvgrpc/client_conn.go
  • client-go/nvgrpc/client_conn_test.go
  • client-go/nvgrpc/config.go
  • client-go/nvgrpc/config_test.go
  • client-go/nvgrpc/interceptors.go
  • client-go/nvgrpc/interceptors_test.go
  • client-go/nvgrpc/options.go
  • client-go/nvgrpc/options_test.go
  • client-go/nvgrpc/watcher.go
  • client-go/nvgrpc/watcher_test.go
  • client-go/version/version.go
  • client-go/version/version_test.go
✅ Files skipped from review due to trivial changes (4)
  • api/hack/boilerplate.go.txt
  • client-go/examples/controller-shim/README.md
  • client-go/hack/boilerplate_overlay.go.txt
  • api/device/v1alpha1/doc.go
🚧 Files skipped from review as they are similar to previous changes (22)
  • .coderabbit.yaml
  • client-go/hack/apply-overlays.sh
  • .versions.yaml
  • api/device/v1alpha1/gpu_conversion_test.go
  • client-go/nvgrpc/options_test.go
  • client-go/version/version_test.go
  • .gitignore
  • client-go/hack/boilerplate.go.txt
  • client-go/nvgrpc/interceptors.go
  • client-go/examples/basic-client/main.go
  • client-go/nvgrpc/client_conn_test.go
  • client-go/nvgrpc/client_conn.go
  • client-go/nvgrpc/config.go
  • client-go/nvgrpc/watcher_test.go
  • client-go/nvgrpc/interceptors_test.go
  • client-go/nvgrpc/options.go
  • api/device/v1alpha1/gpu_conversion.go
  • client-go/examples/streaming-daemon/README.md
  • client-go/hack/overlays/client/versioned/clientset.go
  • client-go/README.md
  • client-go/examples/README.md
  • client-go/examples/fake-server/README.md
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.go: Follow standard Go conventions with gofmt and golint
Use structured logging via log/slog in Go code
Wrap errors with context using fmt.Errorf("context: %w", err) in Go code
Within retry.RetryOnConflict blocks, return errors without wrapping to preserve retry behavior
Use meaningful variable names such as synced over ok for cache sync checks
Use client-go for Kubernetes API interactions in Go code
Prefer informers over direct API calls for watching Kubernetes resources
Implement proper shutdown handling with context cancellation in Go code
Package-level godoc required for all Go packages
Function comments required for all exported Go functions
Use inline comments for complex logic only in Go code
TODO comments should reference issues in Go code
Extract informer event handler setup into helper methods
Use separate informers for different Kubernetes resource types

Files:

  • client-go/version/version.go
  • client-go/examples/streaming-daemon/main.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go
  • client-go/examples/controller-shim/main.go
  • client-go/nvgrpc/config_test.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • api/device/v1alpha1/register.go
  • api/device/v1alpha1/gpu_types.go
  • client-go/nvgrpc/watcher.go
  • client-go/examples/fake-server/main.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • api/device/v1alpha1/converter.go
**/*_test.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*_test.go: Use envtest for testing Kubernetes controllers instead of fake clients
Use testify/assert and testify/require for assertions in Go tests
Write table-driven tests when testing multiple scenarios in Go
Name Go tests descriptively using format: TestFunctionName_Scenario_ExpectedBehavior

Files:

  • client-go/nvgrpc/config_test.go
  • client-go/hack/overlays/client/versioned/integration_test.go
**/go.mod

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use go.mod for each service as a separate Go module with semantic import versioning

Files:

  • client-go/go.mod
  • api/go.mod
🧠 Learnings (23)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: All files must include Apache 2.0 license header

Applied to files:

  • Makefile
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Follow standard Go conventions with gofmt and golint

Applied to files:

  • Makefile
  • .gitattributes
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/go.mod : Use `go.mod` for each service as a separate Go module with semantic import versioning

Applied to files:

  • Makefile
  • client-go/go.mod
  • api/go.mod
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Keep Go dependencies minimal and up-to-date

Applied to files:

  • Makefile
  • client-go/go.mod
  • api/go.mod
  • api/Makefile
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use meaningful variable names such as `synced` over `ok` for cache sync checks

Applied to files:

  • Makefile
  • client-go/examples/controller-shim/main.go
  • client-go/hack/overlays/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : TODO comments should reference issues in Go code

Applied to files:

  • client-go/version/version.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/go.mod
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Package-level godoc required for all Go packages

Applied to files:

  • client-go/version/version.go
  • client-go/examples/streaming-daemon/main.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/examples/controller-shim/main.go
  • api/device/v1alpha1/gpu_types.go
  • client-go/nvgrpc/watcher.go
  • client-go/examples/fake-server/main.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Function comments required for all exported Go functions

Applied to files:

  • client-go/version/version.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/examples/controller-shim/main.go
  • client-go/nvgrpc/watcher.go
  • client-go/examples/fake-server/main.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to data-models/protobufs/**/*.proto : Include comprehensive comments for all fields in Protocol Buffer messages

Applied to files:

  • api/proto/device/v1alpha1/gpu.proto
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to data-models/protobufs/**/*.proto : Use semantic versioning for breaking changes in Protocol Buffer messages

Applied to files:

  • api/proto/device/v1alpha1/gpu.proto
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code

Applied to files:

  • .gitattributes
  • client-go/DEVELOPMENT.md
  • client-go/go.mod
  • client-go/examples/basic-client/README.md
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • api/go.mod
  • api/Makefile
  • client-go/Makefile
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Implement proper shutdown handling with context cancellation in Go code

Applied to files:

  • client-go/examples/streaming-daemon/main.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/nvgrpc/watcher.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Use `envtest` for testing Kubernetes controllers instead of fake clients

Applied to files:

  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/nvgrpc/config_test.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/go.mod
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Prefer informers over direct API calls for watching Kubernetes resources

Applied to files:

  • client-go/examples/controller-shim/main.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/go.mod
  • client-go/nvgrpc/watcher.go
  • api/go.mod
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use separate informers for different Kubernetes resource types

Applied to files:

  • client-go/examples/controller-shim/main.go
  • client-go/hack/overlays/client/versioned/integration_test.go
📚 Learning: 2025-12-22T16:16:24.320Z
Learnt from: pteranodan
Repo: NVIDIA/NVSentinel PR: 607
File: client-go/nvgrpc/config_test.go:61-80
Timestamp: 2025-12-22T16:16:24.320Z
Learning: In Go tests across the repository, avoid introducing the testify dependency for simple equality/inequality checks. Use the standard testing package assertions (t.Error, t.Errorf, t.Fatal, etc.) for straightforward checks. Reserve third-party assertion libraries for complex scenarios that require richer diagnostics or expressive matchers.

Applied to files:

  • client-go/nvgrpc/config_test.go
  • client-go/hack/overlays/client/versioned/integration_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Write table-driven tests when testing multiple scenarios in Go

Applied to files:

  • client-go/nvgrpc/config_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Name Go tests descriptively using format: `TestFunctionName_Scenario_ExpectedBehavior`

Applied to files:

  • client-go/nvgrpc/config_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Aim for >80% test coverage on critical paths in Go code

Applied to files:

  • client-go/nvgrpc/config_test.go
📚 Learning: 2025-12-22T16:16:24.320Z
Learnt from: pteranodan
Repo: NVIDIA/NVSentinel PR: 607
File: client-go/nvgrpc/config_test.go:61-80
Timestamp: 2025-12-22T16:16:24.320Z
Learning: In the NVIDIA/NVSentinel repository, prefer not to introduce a dependency on `stretchr/testify` for simple comparison assertions in Go tests. Use standard `testing` package assertions (t.Error, t.Errorf, etc.) for straightforward checks.

Applied to files:

  • client-go/go.mod
  • api/go.mod
📚 Learning: 2025-11-04T06:31:02.147Z
Learnt from: Gyan172004
Repo: NVIDIA/NVSentinel PR: 223
File: platform-connectors/pkg/nodemetadata/processor.go:0-0
Timestamp: 2025-11-04T06:31:02.147Z
Learning: In platform-connectors/pkg/nodemetadata/processor.go, the NewProcessor function does not perform a nil check on the config parameter because the caller is expected to guarantee a non-nil config is provided.

Applied to files:

  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
📚 Learning: 2025-12-01T17:53:20.067Z
Learnt from: jtschelling
Repo: NVIDIA/NVSentinel PR: 455
File: docs/designs/013-remediation-plugins.md:162-204
Timestamp: 2025-12-01T17:53:20.067Z
Learning: Code examples in design documents (docs/designs/) in the NVSentinel repository are illustrative stubs meant to show intent and architectural concepts, and do not need to be 100% correct or complete implementations (e.g., undefined variables, missing error handling, incomplete struct initialization are acceptable).

Applied to files:

  • api/go.mod
🧬 Code graph analysis (9)
client-go/examples/streaming-daemon/main.go (6)
client-go/hack/overlays/client/versioned/clientset.go (2)
  • New (79-83)
  • NewForConfigAndClient (48-65)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (2)
  • New (58-63)
  • NewForConfigAndClient (39-44)
client-go/nvgrpc/config.go (3)
  • NvidiaDeviceAPITargetEnvVar (28-28)
  • DefaultNvidiaDeviceAPISocket (31-31)
  • Config (41-49)
client-go/nvgrpc/options.go (4)
  • DialOption (23-23)
  • WithLogger (32-36)
  • WithUnaryInterceptor (39-43)
  • WithStreamInterceptor (46-50)
client-go/nvgrpc/client_conn.go (1)
  • ClientConnFor (26-72)
api/device/v1alpha1/gpu_types.go (1)
  • GPU (55-61)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (1)
  • GPUInterface (22-27)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1)
api/device/v1alpha1/gpu_conversion.go (1)
  • FromProto (25-32)
client-go/hack/overlays/client/versioned/integration_test.go (4)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/hack/overlays/client/versioned/clientset.go (2)
  • NewForConfigAndClient (48-65)
  • New (79-83)
api/device/v1alpha1/gpu_types.go (1)
  • GPU (55-61)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
api/device/v1alpha1/register.go (1)
api/device/v1alpha1/gpu_types.go (2)
  • GPU (55-61)
  • GPUList (67-71)
api/device/v1alpha1/gpu_types.go (1)
store-client/pkg/query/builder.go (1)
  • Condition (30-37)
client-go/examples/fake-server/main.go (3)
client-go/nvgrpc/config.go (2)
  • NvidiaDeviceAPITargetEnvVar (28-28)
  • DefaultNvidiaDeviceAPISocket (31-31)
api/device/v1alpha1/gpu_types.go (3)
  • GPU (55-61)
  • GPUSpec (24-30)
  • GPUStatus (35-45)
api/device/v1alpha1/gpu_conversion.go (1)
  • ToProto (35-40)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (4)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (2)
  • GPUsGetter (17-19)
  • GPUInterface (22-27)
client-go/hack/overlays/client/versioned/clientset.go (4)
  • NewForConfig (32-44)
  • NewForConfigAndClient (48-65)
  • NewForConfigOrDie (69-76)
  • New (79-83)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/nvgrpc/client_conn.go (1)
  • ClientConnFor (26-72)
api/device/v1alpha1/converter.go (2)
api/device/v1alpha1/gpu_types.go (3)
  • GPU (55-61)
  • GPUSpec (24-30)
  • GPUStatus (35-45)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
🪛 checkmake (0.2.2)
client-go/Makefile

[warning] 187-187: Target "tools" should be declared PHONY.

(phonydeclared)

🔇 Additional comments (41)
client-go/nvgrpc/config_test.go (3)

20-59: LGTM! Excellent precedence testing.

The test thoroughly validates Target precedence (explicit argument → environment variable → default) using a clear table-driven approach and proper environment isolation via t.Setenv.

Based on learnings, standard library assertions are appropriate for these simple equality checks.


61-80: LGTM! UserAgent default behavior properly tested.

Both subtests correctly validate UserAgent handling: default population when empty and preservation of custom values.

Based on learnings, standard library assertions are appropriate for these simple checks.


82-120: LGTM! Validation logic comprehensively tested.

The test covers essential validation scenarios (valid config, missing target, missing user agent) with correct error assertion logic.

Based on learnings, standard library error assertions are appropriate here.

Makefile (1)

343-343: LGTM! Appropriate exclusion for generated overlay code.

The ignore pattern for **/hack/** aligns with the overlay-based code generation workflow introduced in this PR. This prevents the license header linter from flagging generated or overlay-driven content in hack directories.

client-go/examples/basic-client/README.md (1)

1-38: Documentation is clear and well-structured.

The README provides a solid reference implementation guide covering client initialization, K8s-native verbs, and metadata inspection. The instructions for running with and without root privileges are clear, and the expected output examples are helpful.

.gitattributes (1)

1-16: Excellent practice for managing generated code visibility.

The linguist-generated attributes will significantly improve PR review experience by hiding auto-generated code (DeepCopy, Protobuf bindings, client libraries) from diffs. This aligns with the extensive code generation workflow introduced in this PR.

api/go.mod (1)

3-34: Dependency updates look appropriate.

The Go version bump to 1.25.5 includes important security fixes. The addition of google/go-cmp and the proper declaration of k8s.io/apimachinery as a direct dependency align with the API module's use of Kubernetes types and testing utilities.

client-go/go.mod (1)

1-74: Module dependencies are well-structured and version-aligned.

The go.mod correctly establishes the client-go module with proper dependency versions. All Kubernetes modules are aligned to v0.34.1, and the inclusion of controller-runtime v0.22.4 enables advanced informer and cache patterns. The replace directive for the local API module is appropriate.

client-go/DEVELOPMENT.md (1)

1-105: Comprehensive and well-organized development guide.

The DEVELOPMENT.md provides clear workflow instructions, prerequisites, and explains the code generation pipeline effectively. The mermaid diagram is particularly helpful for visualizing the multi-stage generation process. The warnings about not editing generated files directly are appropriately emphasized and will help prevent common mistakes.

client-go/hack/overlays/client/versioned/integration_test.go (2)

33-252: Comprehensive end-to-end test coverage.

The test suite effectively validates the complete integration stack:

  • gRPC transport layer with bufconn for in-process testing
  • Standard K8s verbs (Get, List, Watch)
  • Informer synchronization and cache updates
  • Controller-runtime compatibility

The test structure is well-organized with clear subtests, appropriate timeouts, and good use of context cancellation.


256-335: Thread-safe mock server implementation.

The mock GPU server correctly uses sync.RWMutex to protect concurrent access to the GPU map. The channel-based event mechanism for WatchGpus is appropriate and the buffering (10 events) provides reasonable headroom for test scenarios.

client-go/nvgrpc/watcher.go (3)

66-76: Proper idempotent shutdown implementation.

The use of sync.Once ensures thread-safe, idempotent shutdown. This correctly addresses the race condition that could occur with manual double-close protection.


138-170: Excellent error mapping for informer compatibility.

The sendError function correctly maps gRPC status codes to Kubernetes status codes. Particularly noteworthy is the mapping of OutOfRange, ResourceExhausted, and InvalidArgument to 410 Expired (lines 147-150), which is critical for triggering informer re-list operations when the watch stream becomes stale.


84-136: Robust event loop with proper cleanup.

The receive() loop correctly handles:

  • EOF and cancellation as normal shutdown conditions
  • Event type mapping to Kubernetes watch.EventType
  • Structured logging with appropriate verbosity levels
  • Cleanup via deferred Stop() and result channel closure

The implementation follows best practices for context cancellation and proper shutdown handling.

Based on coding guidelines, proper shutdown handling with context cancellation is required in Go code.

client-go/version/version.go (1)

22-35: LGTM!

The version variables and UserAgent() function are well-documented and correctly implemented. The typo from the previous review has been fixed.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1)

14-23: LGTM!

The Next() method correctly receives from the stream, converts the protobuf object using FromProto, and returns the event type with the converted object. Error handling is appropriate.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1)

17-24: LGTM!

The ClientConn() method is well-documented, clearly explaining that the fake implementation uses an ObjectTracker memory store rather than an actual gRPC connection. Returning nil is acceptable for a fake implementation.

api/device/v1alpha1/register.go (1)

29-44: LGTM!

The scheme registration follows standard Kubernetes API patterns. SchemeBuilder and AddToScheme are properly documented with inline comments, and addKnownTypes correctly registers GPU and GPUList types with the scheme.

client-go/examples/streaming-daemon/main.go (3)

15-20: LGTM!

Good package-level documentation that clearly explains the example's purpose as a long-running, event-driven agent with Watch stream and custom interceptors.


47-60: LGTM!

The target resolution correctly uses the canonical constants from nvgrpc and the tracing interceptor properly injects metadata into outgoing requests.


92-103: LGTM!

Proper shutdown handling with signal.NotifyContext for graceful termination on SIGINT/SIGTERM. The List operation with error handling is correctly implemented.

api/proto/device/v1alpha1/gpu.proto (2)

53-78: LGTM!

The Gpu and GpuList messages follow Kubernetes Resource Model patterns correctly. The metadata fields (ObjectMeta, ListMeta) enable proper resource versioning and watch semantics. The documentation clearly explains the resource naming convention.


152-167: LGTM!

The resource_version fields in ListGpusRequest and WatchGpusRequest enable clients to list/watch resources at a specific version, supporting proper List-then-Watch patterns and optimistic concurrency. Good documentation explains the purpose.

client-go/examples/controller-shim/main.go (3)

15-20: LGTM!

Good package-level documentation explaining the controller-shim pattern and how it bypasses the standard Kubernetes API server.


85-106: LGTM!

The NewInformer implementation correctly:

  1. Injects the gRPC-backed informer for GPU objects
  2. Merges required indexers while avoiding conflicts
  3. Falls back to standard informers for non-GPU objects (previously raised issue addressed)

65-69: The SharedInformerFactory must be explicitly started or properly integrated with the manager.

The code creates a SharedInformerFactory without starting it. The comment claiming "the Manager will start the injected informer" is incorrect: if this factory is instantiated separately without being passed to a controller-runtime source or the manager's cache, it will not be started automatically. Either call factory.Start(ctx) explicitly before using the informer, or integrate it with controller-runtime's cache via cache.Options.NewInformer so the manager handles its lifecycle.

client-go/examples/fake-server/main.go (3)

15-20: LGTM!

Good package-level documentation explaining the fake server's purpose for local testing and development.


135-169: LGTM!

The simulateChanges() implementation correctly:

  1. Uses proper mutex synchronization
  2. Increments ResourceVersion on each update (K8s watch semantics)
  3. Toggles Ready status and updates LastTransitionTime
  4. Makes a deep copy before broadcasting to avoid data races

210-260: LGTM!

The WatchGpus implementation follows proper streaming patterns:

  1. Sends initial ADDED events for all GPUs
  2. Registers for updates via a buffered channel
  3. Properly cleans up the listener on disconnect
  4. Handles context cancellation gracefully
api/device/v1alpha1/gpu_types.go (1)

21-71: LGTM! Type definitions follow Kubernetes conventions.

The GPU CRD type definitions are well-structured:

  • Proper separation of Spec and Status
  • Correct codegen markers for read-only, non-namespaced resources
  • Clear field documentation with format examples
  • Standard use of metav1 types
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (2)

9-22: LGTM! Interface and client structure follow client-go patterns.

The interface and struct definitions align with standard Kubernetes client-go conventions.


46-73: LGTM! Remaining constructors and accessor correctly implemented.

The NewForConfigOrDie, New, and ClientConn methods follow standard client-go patterns with appropriate nil-safety in the accessor.

api/Makefile (3)

19-59: LGTM! Variable definitions are well-structured.

The Makefile variables are properly defined with clear separation of concerns. The API_PKGS_COMMA variable (line 37) correctly addresses the previous review's concern.


86-142: LGTM! Code generation workflow is well-orchestrated.

The Makefile targets implement a clean code-generation pipeline:

  • Proper dependency chaining ensures generated code is up-to-date before build/test
  • The deepcopy-gen target now correctly uses API_PKGS_COMMA (line 131)
  • Test exclusions appropriately skip generated code directories

169-205: LGTM! Tool installation logic is robust.

The go-install-tool macro correctly:

  • Maintains versioned binaries to avoid unnecessary re-downloads
  • Propagates GOTOOLCHAIN to ensure consistent Go versions
  • Creates symlinks for convenient access
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (1)

29-87: LGTM! Client implementation follows gRPC and client-go best practices.

The GPU client implementation is well-structured:

  • Proper proto-to-internal conversions using FromProto/FromProtoList
  • Correct context cancellation handling in Watch method
  • Appropriate logging verbosity levels for different operations
  • Error propagation is clean and consistent
client-go/Makefile (3)

19-83: LGTM! Variable definitions are comprehensive and well-organized.

The Makefile variables follow a consistent pattern with the API Makefile:

  • Clear module and versioning metadata
  • Proper string manipulation for code generation tools
  • Centralized version management via .versions.yaml
  • Appropriate linker flags for version injection

89-149: LGTM! Code generation workflow is properly orchestrated.

The Makefile targets implement a well-designed multi-stage code generation pipeline:

  • Dependency chain ensures correct build order (install-tools → client-gen → overlays → lister-gen → informer-gen)
  • Test and build exclusions appropriately skip generated code and overlays
  • Code generator arguments correctly reference cross-package dependencies

178-213: LGTM! Tool installation follows established patterns.

The tool installation logic is consistent with the API Makefile and correctly handles versioned binaries with GOTOOLCHAIN propagation.

api/device/v1alpha1/converter.go (2)

106-133: LGTM! Helper functions are correctly implemented.

The helper functions properly:

  • Generate TypeMeta with full group/version APIVersion format using SchemeGroupVersion.String() (lines 110, 118) - addressing the previous review's concern
  • Handle nil timestamps safely in FromProtobufTimestamp (lines 124-126)
  • Perform clean bidirectional timestamp conversions

23-104: LGTM! Converter interface is well-designed for code generation.

The interface provides comprehensive bidirectional conversion methods with proper goverter annotations:

  • Clear field mappings for name differences (e.g., UuidUUID)
  • Appropriate ignore directives for protobuf internals
  • Extension of helper functions for TypeMeta and timestamp conversions

@pteranodan
Copy link
Contributor Author

@coderabbitai full review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 22, 2025

✅ Actions performed

Full review triggered.

@pteranodan pteranodan force-pushed the add-go-sdk branch 3 times, most recently from 3efcf77 to cdb7585 Compare December 22, 2025 17:07
@pteranodan
Copy link
Contributor Author

@coderabbitai full review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 22, 2025

✅ Actions performed

Full review triggered.

Copy link
Contributor

@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

♻️ Duplicate comments (14)
client-go/examples/basic-client/README.md (1)

20-38: Clarify expected output alignment with "Running without Root" instructions.

The "Running without Root" section (line 24) overrides the socket to unix:///tmp/device-api.sock, but the "Expected Output" section (line 31) shows the default socket path unix:///var/run/nvidia-device-api/device-api.sock. This mismatch is confusing—it's unclear whether the expected output corresponds to the default case (with sudo) or the "without Root" variant.

If the expected output is for the default case, restructure the documentation to make this explicit. If it's for the "without Root" case, update line 31 to reflect the overridden socket path.

🔎 Suggested clarification

Option A: Separate expected outputs for each case:

 ## Expected Output

+### Running as Root
+
 ```text
-"level"=0 "msg"="discovered GPUs" "count"=8 "target"="unix:///var/run/nvidia-device-api/device-api.sock"
+"level"=0 "msg"="discovered GPUs" "count"=8 "target"="unix:///var/run/nvidia-device-api/device-api.sock"
 "level"=0 "msg"="details" "name"="gpu-0" "uuid"="GPU-6e5b6a57..."
 ...

+### Running without Root
+
+text +"level"=0 "msg"="discovered GPUs" "count"=8 "target"="unix:///tmp/device-api.sock" +"level"=0 "msg"="details" "name"="gpu-0" "uuid"="GPU-6e5b6a57..." +... +


Option B: Update the single expected output to match the most recent instructions (line 24):

```diff
-"level"=0 "msg"="discovered GPUs" "count"=8 "target"="unix:///var/run/nvidia-device-api/device-api.sock"
+"level"=0 "msg"="discovered GPUs" "count"=8 "target"="unix:///tmp/device-api.sock"
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1)

25-27: CloseSend() is inappropriate for server-streaming RPCs.

For server-streaming RPCs like WatchGpus, the client only receives messages and does not send after the initial request. Calling CloseSend() is not the correct way to close a receive-only stream and may cause errors or fail to properly release resources. Either return nil directly or rely on context cancellation to properly close the stream.

🔎 Suggested fix
 func (a *gpuStreamAdapter) Close() error {
-	return a.stream.CloseSend()
+	return nil
 }

Alternatively, if cleanup is needed, consider using stream.Context().Done() to detect when the stream is closed by context cancellation.

client-go/examples/fake-server/main.go (1)

195-208: Populate ListMeta with ResourceVersion.

The ListGpus response does not include Metadata.ResourceVersion, which is needed for clients to establish a watch from a consistent point using the List-then-Watch pattern. Consider tracking a global resource version and populating it in the response.

🔎 Suggested fix
 func (s *fakeServer) ListGpus(ctx context.Context, req *pb.ListGpusRequest) (*pb.ListGpusResponse, error) {
 	s.mu.RLock()
 	defer s.mu.RUnlock()
 
 	gpuList := &pb.GpuList{
+		Metadata: &pb.ListMeta{
+			ResourceVersion: "1", // Or compute max from s.gpus
+		},
 		Items: make([]*pb.Gpu, 0, len(s.gpus)),
 	}
client-go/version/version.go (1)

15-15: Add package-level godoc comment.

Per coding guidelines, all Go packages require package-level documentation. Add a comment above the package declaration describing the purpose of the version package.

🔎 Suggested documentation
+// Package version provides build-time version information and user-agent
+// string generation for the nvidia-device-api-client.
 package version

As per coding guidelines, package-level godoc is required for all Go packages.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (2)

1-1: Add package-level godoc comment.

The coding guidelines require package-level documentation for all Go packages. The fake package should have a comment describing its purpose.

As per coding guidelines, package-level godoc is required for all Go packages.


13-15: Add function comment for exported method.

The GPUs() method is exported but lacks documentation. Add a comment describing what this method returns and its purpose in the fake client.

As per coding guidelines, function comments are required for all exported Go functions.

api/proto/device/v1alpha1/gpu.proto (1)

35-37: Fix indentation inconsistency.

Lines 35-37 use tabs while surrounding comment lines use spaces. Normalize the indentation by replacing tabs with spaces to maintain consistency throughout the file.

client-go/examples/streaming-daemon/main.go (1)

146-148: Fix misleading log message.

The log message says "context timeout reached" but the context is created from signal.NotifyContext (line 93), which cancels on SIGINT/SIGTERM signals, not on timeout.

🔎 Suggested fix
 			case <-ctx.Done():
-				logger.Info("context timeout reached, stopping watch")
+				logger.Info("received shutdown signal, stopping watch")
 				return
client-go/hack/overlays/client/versioned/integration_test.go (1)

209-213: Avoid calling t.Errorf from a goroutine.

Calling t.Errorf from a goroutine is unsafe and can cause race conditions or panics if the test completes before the goroutine executes. Since c.Start(ctx) blocks until context cancellation and typically only returns errors on shutdown, consider using an error channel or simply logging/ignoring the error.

🔎 Suggested fix using error channel
+		errCh := make(chan error, 1)
 		go func() {
-			if err := c.Start(ctx); err != nil {
-				t.Errorf("Cache failed to start: %v", err)
-			}
+			errCh <- c.Start(ctx)
 		}()
+
+		// Defer check for cache start errors (only relevant after test completes)
+		defer func() {
+			select {
+			case err := <-errCh:
+				if err != nil && ctx.Err() == nil {
+					t.Errorf("Cache failed to start: %v", err)
+				}
+			default:
+			}
+		}()
client-go/examples/controller-shim/main.go (2)

135-152: Add godoc comments for exported methods Reconcile and SetupWithManager.

Per coding guidelines, function comments are required for all exported Go functions.

Suggested additions
+// Reconcile retrieves the requested GPU resource from the gRPC-backed cache
+// and logs its name and UUID. Returns without error if the GPU is not found.
 func (r *GPUReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
 	log := ctrl.LoggerFrom(ctx)

 	var gpu devicev1alpha1.GPU
 	// The Get call is transparently routed through the injected gRPC-backed informer.
 	if err := r.Get(ctx, req.NamespacedName, &gpu); err != nil {
 		return ctrl.Result{}, client.IgnoreNotFound(err)
 	}

 	log.Info("Reconciled GPU", "name", gpu.Name, "uuid", gpu.Spec.UUID)
 	return ctrl.Result{}, nil
 }

+// SetupWithManager registers the GPUReconciler with the provided manager,
+// configuring it to watch GPU resources.
 func (r *GPUReconciler) SetupWithManager(mgr ctrl.Manager) error {

65-70: The gRPC-backed informer factory is never started.

The comment on line 67 states the Manager will start the injected informer, but controller-runtime only starts informers created through its own cache machinery. The externally provided gpuInformer from the gRPC factory must be started explicitly; otherwise, the cache will never populate.

Suggested fix
 	factory := informers.NewSharedInformerFactory(clientset, 10*time.Minute)
 	gpuInformer := factory.Device().V1alpha1().GPUs().Informer()
+
+	// Start the informer factory before manager starts.
+	// Controller-runtime won't start externally-provided informers.
+	ctx := ctrl.SetupSignalHandler()
+	factory.Start(ctx.Done())

Then move ctx := ctrl.SetupSignalHandler() before the factory creation and remove the duplicate declaration at line 121.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1)

1-1: Package-level documentation is still missing.

As noted in the previous review, this package lacks the required package-level godoc comment.

client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (1)

1-1: Package-level documentation is still missing.

As noted in the previous review, this package lacks the required package-level godoc comment.

client-go/Makefile (1)

187-187: Declare the tools target as PHONY.

As noted in the previous review and confirmed by static analysis, the tools target should be declared .PHONY since it doesn't produce a file output.

🧹 Nitpick comments (7)
client-go/nvgrpc/config_test.go (1)

82-120: LGTM with optional suggestion for completeness.

The validation test correctly covers the essential scenarios: valid config, missing target, and missing user agent. The test logic is sound and follows the table-driven pattern appropriately.

Optional: Consider adding edge case test

For completeness, you could add a test case where both Target and UserAgent are empty:

{
    name: "Missing both target and user agent",
    cfg: Config{},
    wantErr: true,
},

This would ensure full edge case coverage, though the current tests already validate the core validation logic.

api/go.mod (1)

11-17: Consider separating direct and indirect dependencies.

While k8s.io/apimachinery is now correctly declared as a direct dependency (past issue resolved), the current formatting mixes direct and indirect dependencies in the same require block. For better clarity, consider moving k8s.io/apimachinery to the direct dependencies block at lines 5-9.

🔎 Suggested reorganization
 require (
 	github.com/google/go-cmp v0.7.0
 	google.golang.org/grpc v1.77.0
 	google.golang.org/protobuf v1.36.11
+	k8s.io/apimachinery v0.34.1
 )
 
 require (
 	golang.org/x/net v0.47.0 // indirect
 	golang.org/x/sys v0.38.0 // indirect
 	golang.org/x/text v0.31.0 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846 // indirect
-	k8s.io/apimachinery v0.34.1
 )

After making this change, run go mod tidy to ensure consistency.

client-go/nvgrpc/client_conn.go (1)

15-15: Add package-level documentation.

Per coding guidelines, package-level godoc is required for all Go packages. Consider adding documentation describing the purpose of the nvgrpc package.

🔎 Suggested documentation
+// Package nvgrpc provides gRPC client connectivity for the NVIDIA Device API,
+// including connection configuration, transport credentials, keepalive settings,
+// and observability interceptors.
 package nvgrpc
client-go/nvgrpc/interceptors_test.go (1)

30-42: Remove unused expectedCode field from test struct.

The expectedCode field is defined but never used in the test assertions. Either remove it or add an assertion that verifies the response code matches expectations.

🔎 Proposed fix (remove unused field)
 	tests := []struct {
 		name         string
 		method       string
 		log          bool
 		invokerErr   error
-		expectedCode codes.Code
 	}{
-		{"Returns OK code for successful call", "/svc/success", true, nil, codes.OK},
-		{"Returns internal status error on internal error", "/svc/internal_error", true, status.Error(codes.Internal, "fail"), codes.Internal},
-		{"Returns canceled status error when canceled", "/svc/cancel", true, status.Error(codes.Canceled, ""), codes.Canceled},
-		{"Returns deadline exceeded status error on timeout", "/svc/timeout", true, status.Error(codes.DeadlineExceeded, ""), codes.DeadlineExceeded},
-		{"Does not log if logger disabled", "/svc/skip_log", false, nil, codes.OK},
+		{"Returns OK code for successful call", "/svc/success", true, nil},
+		{"Returns internal status error on internal error", "/svc/internal_error", true, status.Error(codes.Internal, "fail")},
+		{"Returns canceled status error when canceled", "/svc/cancel", true, status.Error(codes.Canceled, "")},
+		{"Returns deadline exceeded status error on timeout", "/svc/timeout", true, status.Error(codes.DeadlineExceeded, "")},
+		{"Does not log if logger disabled", "/svc/skip_log", false, nil},
 	}
client-go/examples/controller-shim/main.go (1)

130-133: Add godoc comment for the exported GPUReconciler type.

Per coding guidelines, exported types should have documentation comments.

Suggested addition
+// GPUReconciler reconciles GPU resources using a gRPC-backed cache.
+// It retrieves GPU state from the local NVIDIA Device API and logs reconciliation events.
 type GPUReconciler struct {
 	client.Client
 }
client-go/nvgrpc/interceptors.go (1)

57-85: Consider aligning verbosity levels between unary and stream interceptors.

The unary interceptor logs success at V(6) while the stream interceptor logs success at V(4). This inconsistency may confuse operators adjusting log verbosity. If intentional (e.g., streams are less frequent), consider adding a brief comment explaining the rationale.

 	if err != nil || logger.V(4).Enabled() {
+		// Stream establishment is typically less frequent than unary RPCs,
+		// so we log at a lower verbosity level (V(4) vs V(6) for unary).
 		s := status.Convert(err)
client-go/hack/overlays/client/versioned/clientset.go (1)

1-10: Add copyright header to the overlay file.

Other files in the PR include the NVIDIA Apache 2.0 copyright header. For consistency, this overlay should also include it.

Suggested addition
+// Copyright (c) 2025, NVIDIA CORPORATION.  All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 package versioned
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d97ed84 and cfd3179.

⛔ Files ignored due to path filters (28)
  • api/device/v1alpha1/zz_generated.conversion.go is excluded by !api/**/zz_generated.*
  • api/device/v1alpha1/zz_generated.deepcopy.go is excluded by !api/**/zz_generated.*
  • api/gen/go/device/v1alpha1/gpu.pb.go is excluded by !**/*.pb.go, !**/gen/**, !api/gen/**
  • api/go.sum is excluded by !**/*.sum
  • client-go/client/versioned/clientset.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/clientset_generated.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/fake/register.go is excluded by !client-go/client/**
  • client-go/client/versioned/integration_test.go is excluded by !client-go/client/**
  • client-go/client/versioned/scheme/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/scheme/register.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/device_client.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/doc.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/fake/fake_gpu.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/generated_expansion.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/gpu.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go is excluded by !client-go/client/**
  • client-go/go.sum is excluded by !**/*.sum
  • client-go/informers/externalversions/device/interface.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/device/v1alpha1/gpu.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/device/v1alpha1/interface.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/factory.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/generic.go is excluded by !client-go/informers/**
  • client-go/informers/externalversions/internalinterfaces/factory_interfaces.go is excluded by !client-go/informers/**
  • client-go/listers/device/v1alpha1/expansion_generated.go is excluded by !client-go/listers/**
  • client-go/listers/device/v1alpha1/gpu.go is excluded by !client-go/listers/**
📒 Files selected for processing (50)
  • .coderabbit.yaml
  • .gitattributes
  • .gitignore
  • .versions.yaml
  • Makefile
  • api/Makefile
  • api/device/v1alpha1/converter.go
  • api/device/v1alpha1/doc.go
  • api/device/v1alpha1/gpu_conversion.go
  • api/device/v1alpha1/gpu_conversion_test.go
  • api/device/v1alpha1/gpu_types.go
  • api/device/v1alpha1/register.go
  • api/go.mod
  • api/hack/boilerplate.go.txt
  • api/proto/device/v1alpha1/gpu.proto
  • client-go/DEVELOPMENT.md
  • client-go/Makefile
  • client-go/README.md
  • client-go/examples/README.md
  • client-go/examples/basic-client/README.md
  • client-go/examples/basic-client/main.go
  • client-go/examples/controller-shim/README.md
  • client-go/examples/controller-shim/main.go
  • client-go/examples/fake-server/README.md
  • client-go/examples/fake-server/main.go
  • client-go/examples/streaming-daemon/README.md
  • client-go/examples/streaming-daemon/main.go
  • client-go/go.mod
  • client-go/hack/apply-overlays.sh
  • client-go/hack/boilerplate.go.txt
  • client-go/hack/boilerplate_overlay.go.txt
  • client-go/hack/overlays/client/versioned/clientset.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go
  • client-go/nvgrpc/client_conn.go
  • client-go/nvgrpc/client_conn_test.go
  • client-go/nvgrpc/config.go
  • client-go/nvgrpc/config_test.go
  • client-go/nvgrpc/doc.go
  • client-go/nvgrpc/interceptors.go
  • client-go/nvgrpc/interceptors_test.go
  • client-go/nvgrpc/options.go
  • client-go/nvgrpc/options_test.go
  • client-go/nvgrpc/watcher.go
  • client-go/nvgrpc/watcher_test.go
  • client-go/version/version.go
  • client-go/version/version_test.go
✅ Files skipped from review due to trivial changes (1)
  • client-go/nvgrpc/doc.go
🚧 Files skipped from review as they are similar to previous changes (18)
  • .versions.yaml
  • client-go/examples/streaming-daemon/README.md
  • .gitignore
  • client-go/version/version_test.go
  • api/hack/boilerplate.go.txt
  • api/device/v1alpha1/doc.go
  • client-go/nvgrpc/config.go
  • client-go/nvgrpc/watcher.go
  • api/device/v1alpha1/register.go
  • Makefile
  • api/device/v1alpha1/gpu_conversion_test.go
  • client-go/examples/README.md
  • .coderabbit.yaml
  • client-go/hack/apply-overlays.sh
  • client-go/examples/fake-server/README.md
  • client-go/hack/boilerplate_overlay.go.txt
  • client-go/nvgrpc/watcher_test.go
  • client-go/examples/controller-shim/README.md
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.go: Follow standard Go conventions with gofmt and golint
Use structured logging via log/slog in Go code
Wrap errors with context using fmt.Errorf("context: %w", err) in Go code
Within retry.RetryOnConflict blocks, return errors without wrapping to preserve retry behavior
Use meaningful variable names such as synced over ok for cache sync checks
Use client-go for Kubernetes API interactions in Go code
Prefer informers over direct API calls for watching Kubernetes resources
Implement proper shutdown handling with context cancellation in Go code
Package-level godoc required for all Go packages
Function comments required for all exported Go functions
Use inline comments for complex logic only in Go code
TODO comments should reference issues in Go code
Extract informer event handler setup into helper methods
Use separate informers for different Kubernetes resource types

Files:

  • client-go/nvgrpc/client_conn_test.go
  • client-go/examples/basic-client/main.go
  • client-go/nvgrpc/options_test.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/nvgrpc/interceptors_test.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/hack/overlays/client/versioned/clientset.go
  • client-go/examples/controller-shim/main.go
  • api/device/v1alpha1/gpu_types.go
  • client-go/nvgrpc/config_test.go
  • api/device/v1alpha1/converter.go
  • client-go/nvgrpc/interceptors.go
  • api/device/v1alpha1/gpu_conversion.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go
  • client-go/nvgrpc/options.go
  • client-go/version/version.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/nvgrpc/client_conn.go
  • client-go/examples/streaming-daemon/main.go
  • client-go/examples/fake-server/main.go
**/*_test.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*_test.go: Use envtest for testing Kubernetes controllers instead of fake clients
Use testify/assert and testify/require for assertions in Go tests
Write table-driven tests when testing multiple scenarios in Go
Name Go tests descriptively using format: TestFunctionName_Scenario_ExpectedBehavior

Files:

  • client-go/nvgrpc/client_conn_test.go
  • client-go/nvgrpc/options_test.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/nvgrpc/interceptors_test.go
  • client-go/nvgrpc/config_test.go
**/go.mod

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use go.mod for each service as a separate Go module with semantic import versioning

Files:

  • client-go/go.mod
  • api/go.mod
🧠 Learnings (26)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code
Learnt from: pteranodan
Repo: NVIDIA/NVSentinel PR: 607
File: client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go:15-27
Timestamp: 2025-12-22T16:48:09.264Z
Learning: In the client-go module, files under `hack/overlays/` use the overlay pattern: they are copied into generated code directories and are not compiled standalone. These overlay files may reference types (e.g., `GPUExpansion`) that are generated by Kubernetes code-gen tools and only exist in the final destination. The build excludes overlays via grep patterns like `grep -vE '/hack/overlays/|/examples/'`. Do not flag missing type references in overlay files as compilation errors.
📚 Learning: 2025-12-22T16:16:24.320Z
Learnt from: pteranodan
Repo: NVIDIA/NVSentinel PR: 607
File: client-go/nvgrpc/config_test.go:61-80
Timestamp: 2025-12-22T16:16:24.320Z
Learning: In Go tests across the repository, avoid introducing the testify dependency for simple equality/inequality checks. Use the standard testing package assertions (t.Error, t.Errorf, t.Fatal, etc.) for straightforward checks. Reserve third-party assertion libraries for complex scenarios that require richer diagnostics or expressive matchers.

Applied to files:

  • client-go/nvgrpc/client_conn_test.go
  • client-go/nvgrpc/options_test.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/nvgrpc/interceptors_test.go
  • client-go/nvgrpc/config_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Use `envtest` for testing Kubernetes controllers instead of fake clients

Applied to files:

  • client-go/nvgrpc/client_conn_test.go
  • client-go/go.mod
  • client-go/nvgrpc/options_test.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/nvgrpc/config_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Write table-driven tests when testing multiple scenarios in Go

Applied to files:

  • client-go/nvgrpc/client_conn_test.go
  • client-go/nvgrpc/options_test.go
  • client-go/nvgrpc/config_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Name Go tests descriptively using format: `TestFunctionName_Scenario_ExpectedBehavior`

Applied to files:

  • client-go/nvgrpc/client_conn_test.go
  • client-go/nvgrpc/options_test.go
  • client-go/nvgrpc/config_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code

Applied to files:

  • client-go/nvgrpc/client_conn_test.go
  • .gitattributes
  • client-go/examples/basic-client/main.go
  • client-go/go.mod
  • client-go/README.md
  • client-go/examples/basic-client/README.md
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go
  • client-go/Makefile
  • client-go/version/version.go
  • api/go.mod
  • client-go/DEVELOPMENT.md
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Aim for >80% test coverage on critical paths in Go code

Applied to files:

  • client-go/nvgrpc/client_conn_test.go
  • client-go/nvgrpc/options_test.go
  • client-go/nvgrpc/config_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : TODO comments should reference issues in Go code

Applied to files:

  • client-go/nvgrpc/client_conn_test.go
  • client-go/go.mod
  • client-go/nvgrpc/options_test.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/nvgrpc/options.go
  • client-go/version/version.go
📚 Learning: 2025-12-22T16:48:09.264Z
Learnt from: pteranodan
Repo: NVIDIA/NVSentinel PR: 607
File: client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go:15-27
Timestamp: 2025-12-22T16:48:09.264Z
Learning: In the client-go module, files under `hack/overlays/` use the overlay pattern: they are copied into generated code directories and are not compiled standalone. These overlay files may reference types (e.g., `GPUExpansion`) that are generated by Kubernetes code-gen tools and only exist in the final destination. The build excludes overlays via grep patterns like `grep -vE '/hack/overlays/|/examples/'`. Do not flag missing type references in overlay files as compilation errors.

Applied to files:

  • .gitattributes
  • client-go/go.mod
  • client-go/README.md
  • client-go/hack/boilerplate.go.txt
  • api/device/v1alpha1/gpu_conversion.go
  • client-go/nvgrpc/options.go
  • client-go/Makefile
  • api/Makefile
  • client-go/DEVELOPMENT.md
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Follow standard Go conventions with gofmt and golint

Applied to files:

  • .gitattributes
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/go.mod : Use `go.mod` for each service as a separate Go module with semantic import versioning

Applied to files:

  • client-go/go.mod
  • client-go/Makefile
  • api/go.mod
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Keep Go dependencies minimal and up-to-date

Applied to files:

  • client-go/go.mod
  • api/Makefile
  • api/go.mod
📚 Learning: 2025-12-22T16:16:24.320Z
Learnt from: pteranodan
Repo: NVIDIA/NVSentinel PR: 607
File: client-go/nvgrpc/config_test.go:61-80
Timestamp: 2025-12-22T16:16:24.320Z
Learning: In the NVIDIA/NVSentinel repository, prefer not to introduce a dependency on `stretchr/testify` for simple comparison assertions in Go tests. Use standard `testing` package assertions (t.Error, t.Errorf, etc.) for straightforward checks.

Applied to files:

  • client-go/go.mod
  • client-go/hack/boilerplate.go.txt
  • api/go.mod
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Prefer informers over direct API calls for watching Kubernetes resources

Applied to files:

  • client-go/go.mod
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/examples/controller-shim/main.go
  • api/go.mod
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Use `commons/` for shared utilities across Go modules

Applied to files:

  • client-go/go.mod
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use meaningful variable names such as `synced` over `ok` for cache sync checks

Applied to files:

  • client-go/nvgrpc/options_test.go
  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/examples/controller-shim/main.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: All files must include Apache 2.0 license header

Applied to files:

  • client-go/hack/boilerplate.go.txt
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Implement proper shutdown handling with context cancellation in Go code

Applied to files:

  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go
  • client-go/examples/streaming-daemon/main.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use separate informers for different Kubernetes resource types

Applied to files:

  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/examples/controller-shim/main.go
📚 Learning: 2025-12-22T16:48:09.264Z
Learnt from: pteranodan
Repo: NVIDIA/NVSentinel PR: 607
File: client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go:15-27
Timestamp: 2025-12-22T16:48:09.264Z
Learning: In the client-go module, treat files under client-go/hack/overlays/ as overlay-generated code: they are copied into generated code directories and are not compiled standalone. Do not treat missing type references (e.g., generated by Kubernetes code-gen tools) in overlay files as compilation errors. Build excludes overlays with patterns like grep -vE '/hack/overlays/|/examples/'. Apply this guideline to all files under client-go/hack/overlays/.

Applied to files:

  • client-go/hack/overlays/client/versioned/integration_test.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/hack/overlays/client/versioned/clientset.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Function comments required for all exported Go functions

Applied to files:

  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/examples/controller-shim/main.go
  • client-go/nvgrpc/options.go
  • client-go/version/version.go
  • client-go/examples/fake-server/main.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Package-level godoc required for all Go packages

Applied to files:

  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go
  • client-go/examples/controller-shim/main.go
  • api/device/v1alpha1/gpu_types.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go
  • client-go/version/version.go
  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
  • client-go/examples/streaming-daemon/main.go
  • client-go/examples/fake-server/main.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to data-models/protobufs/**/*.proto : Include comprehensive comments for all fields in Protocol Buffer messages

Applied to files:

  • api/device/v1alpha1/converter.go
  • api/proto/device/v1alpha1/gpu.proto
📚 Learning: 2025-12-01T17:53:20.067Z
Learnt from: jtschelling
Repo: NVIDIA/NVSentinel PR: 455
File: docs/designs/013-remediation-plugins.md:162-204
Timestamp: 2025-12-01T17:53:20.067Z
Learning: Code examples in design documents (docs/designs/) in the NVSentinel repository are illustrative stubs meant to show intent and architectural concepts, and do not need to be 100% correct or complete implementations (e.g., undefined variables, missing error handling, incomplete struct initialization are acceptable).

Applied to files:

  • api/go.mod
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to data-models/protobufs/**/*.proto : Use semantic versioning for breaking changes in Protocol Buffer messages

Applied to files:

  • api/proto/device/v1alpha1/gpu.proto
📚 Learning: 2025-11-04T06:31:02.147Z
Learnt from: Gyan172004
Repo: NVIDIA/NVSentinel PR: 223
File: platform-connectors/pkg/nodemetadata/processor.go:0-0
Timestamp: 2025-11-04T06:31:02.147Z
Learning: In platform-connectors/pkg/nodemetadata/processor.go, the NewProcessor function does not perform a nil check on the config parameter because the caller is expected to guarantee a non-nil config is provided.

Applied to files:

  • client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go
🧬 Code graph analysis (14)
client-go/nvgrpc/client_conn_test.go (4)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/nvgrpc/client_conn.go (1)
  • ClientConnFor (39-87)
client-go/version/version.go (1)
  • UserAgent (28-35)
client-go/nvgrpc/options.go (1)
  • WithLogger (32-36)
client-go/examples/basic-client/main.go (3)
client-go/hack/overlays/client/versioned/clientset.go (2)
  • New (79-83)
  • NewForConfig (32-44)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (2)
  • New (71-76)
  • NewForConfig (29-41)
client-go/nvgrpc/config.go (3)
  • NvidiaDeviceAPITargetEnvVar (28-28)
  • DefaultNvidiaDeviceAPISocket (31-31)
  • Config (41-49)
client-go/nvgrpc/options_test.go (1)
client-go/nvgrpc/options.go (4)
  • DialOption (23-23)
  • WithLogger (32-36)
  • WithUnaryInterceptor (39-43)
  • WithStreamInterceptor (46-50)
client-go/hack/overlays/client/versioned/integration_test.go (5)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/hack/overlays/client/versioned/clientset.go (2)
  • NewForConfigAndClient (48-65)
  • New (79-83)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (2)
  • NewForConfigAndClient (45-57)
  • New (71-76)
api/device/v1alpha1/gpu_types.go (1)
  • GPU (55-61)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
client-go/nvgrpc/interceptors_test.go (1)
client-go/nvgrpc/interceptors.go (2)
  • NewErrorLoggingUnaryInterceptor (27-55)
  • NewErrorLoggingStreamInterceptor (58-85)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu_stream_adapter.go (1)
api/device/v1alpha1/gpu_conversion.go (1)
  • FromProto (25-32)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/fake/fake_device_client.go (1)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (1)
  • GPUInterface (22-27)
client-go/hack/overlays/client/versioned/clientset.go (3)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (6)
  • DeviceV1alpha1Interface (11-14)
  • DeviceV1alpha1Client (17-20)
  • NewForConfig (29-41)
  • NewForConfigAndClient (45-57)
  • NewForConfigOrDie (61-68)
  • New (71-76)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/nvgrpc/client_conn.go (1)
  • ClientConnFor (39-87)
client-go/nvgrpc/config_test.go (2)
client-go/nvgrpc/config.go (3)
  • DefaultNvidiaDeviceAPISocket (31-31)
  • NvidiaDeviceAPITargetEnvVar (28-28)
  • Config (41-49)
client-go/version/version.go (1)
  • UserAgent (28-35)
api/device/v1alpha1/converter.go (2)
api/device/v1alpha1/gpu_types.go (4)
  • GPU (55-61)
  • GPUList (67-71)
  • GPUSpec (24-30)
  • GPUStatus (35-45)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
api/device/v1alpha1/gpu_conversion.go (2)
api/device/v1alpha1/converter.go (1)
  • Converter (30-104)
api/device/v1alpha1/gpu_types.go (2)
  • GPU (55-61)
  • GPUList (67-71)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (5)
api/device/v1alpha1/gpu_types.go (2)
  • GPU (55-61)
  • GPUList (67-71)
client-go/hack/overlays/client/versioned/clientset.go (1)
  • Interface (12-14)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (1)
  • DeviceV1alpha1Client (17-20)
api/device/v1alpha1/gpu_conversion.go (2)
  • FromProto (25-32)
  • FromProtoList (43-48)
client-go/nvgrpc/watcher.go (1)
  • NewWatcher (49-64)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/device_client.go (4)
client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go (2)
  • GPUsGetter (17-19)
  • GPUInterface (22-27)
client-go/hack/overlays/client/versioned/clientset.go (4)
  • NewForConfig (32-44)
  • NewForConfigAndClient (48-65)
  • NewForConfigOrDie (69-76)
  • New (79-83)
client-go/nvgrpc/config.go (1)
  • Config (41-49)
client-go/nvgrpc/client_conn.go (1)
  • ClientConnFor (39-87)
client-go/nvgrpc/client_conn.go (4)
client-go/nvgrpc/config.go (3)
  • Config (41-49)
  • DefaultKeepAliveTime (34-34)
  • DefaultKeepAliveTimeout (37-37)
client-go/nvgrpc/options.go (1)
  • DialOption (23-23)
client-go/version/version.go (1)
  • UserAgent (28-35)
client-go/nvgrpc/interceptors.go (2)
  • NewErrorLoggingUnaryInterceptor (27-55)
  • NewErrorLoggingStreamInterceptor (58-85)
🪛 checkmake (0.2.2)
client-go/Makefile

[warning] 187-187: Target "tools" should be declared PHONY.

(phonydeclared)

@pteranodan pteranodan marked this pull request as draft December 23, 2025 15:22
Signed-off-by: Dan Huenecke <[email protected]>
@pteranodan pteranodan marked this pull request as ready for review January 9, 2026 19:50
Copy link
Contributor

@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: 11

🤖 Fix all issues with AI agents
In @.versions.yaml:
- Around line 49-50: The .versions.yaml entry for goverter is incorrect—update
the goverter key value from 'v1.9.3' to the existing release 'v1.9.2' while
leaving kubernetes_code_gen at 'v0.34.1' unchanged; locate the goverter entry in
the file and replace its version string so the key "goverter" reads 'v1.9.2'.

In @client-go/DEVELOPMENT.md:
- Line 13: Fix the typo in DEVELOPMENT.md by updating the description for the
`version/` entry: replace "fFunctionality" with "Functionality" so the line
reads "`version/`: [Manual] Version injection Functionality via `ldflags`."

In @client-go/examples/streaming-daemon/README.md:
- Around line 19-21: Change the phrasing in the README note to tighten wording:
replace “the exact same URI” with “the same URI” in the sentence that tells
users to override the socket path with the NVIDIA_DEVICE_API_TARGET environment
variable so it reads “…override the socket path with the
NVIDIA_DEVICE_API_TARGET environment variable to the same URI here.” to improve
readability.

In @client-go/tests/integration/device/v1alpha1/clientset_test.go:
- Line 1: This file is missing the required Apache 2.0 license header; add the
standard Apache 2.0 license comment block at the top of the file above the
package declaration in
client-go/tests/integration/device/v1alpha1/clientset_test.go, then run the
repository's license linter (make license-headers-lint) to ensure formatting and
compliance.

In @code-generator/cmd/client-gen/args/gvpackages.go:
- Around line 44-50: NewInputBasePathValue calls v.Set(def) and ignores its
returned error which can hide builder.update() failures; update the constructor
to check the error returned by inputBasePathValue.Set(def) and panic on non-nil
error (consistent with NewGVPackagesValue/NewGVTypesValue) so invalid default
values fail fast—locate NewInputBasePathValue and inputBasePathValue.Set (which
calls builder.update()) and change the call to capture err and panic with a
descriptive message if err != nil.

In @code-generator/cmd/client-gen/generators/client_generator.go:
- Around line 334-355: sanitizePackagePaths assumes context.FindPackages(input)
returns a non-empty slice and dereferences pkgs[0], which can panic if the slice
is empty; after calling context.FindPackages(input) in sanitizePackagePaths,
check if len(pkgs) == 0 and return a descriptive error (e.g., "no packages found
for input %q") before accessing pkgs[0], ensuring ver.Package is only set when a
package is actually available.
- Around line 304-326: The loop in applyGroupOverrides uses
gvs.Versions[0].Version without checking that gvs.Versions is non-empty, which
can panic; update the loop that builds newGroups so it first verifies
len(gvs.Versions) > 0 (or skips/returns an error for empty Versions) before
accessing Versions[0], and handle empty cases by either continuing with gvs
unchanged, setting a safe default version, or returning a clear error; adjust
references in this block that create clientgentypes.GroupVersion and
clientgentypes.GroupVersions to use the validated version value or the chosen
fallback.

In @code-generator/cmd/client-gen/generators/util/tags.go:
- Around line 157-186: The HasVerb method currently ignores the Tags.NoVerbs
flag so +genclient:noVerbs is ineffective; modify Tags.HasVerb to first check if
t.NoVerbs is true and immediately return false for any verb, otherwise preserve
the existing SkipVerbs logic (iterate t.SkipVerbs and return false if verb
matches, true otherwise). Update the Tags.HasVerb implementation to reference
the NoVerbs field before consulting SkipVerbs so generators honor
+genclient:noVerbs.
- Around line 145-155: The Input() and Result() methods currently return (type,
package) but their comments say they should return (package path, type); fix
both by swapping the return values so they return
strings.Join(parts[0:len(parts)-1], ".") first (the package path) and
parts[len(parts)-1] second (the type); do this for extension.Input() and
extension.Result() while preserving the current split logic and single-segment
behavior.
- Around line 223-250: The conflict logic currently overwrites ret.SkipVerbs
when onlyVerbs is specified and never compares the user-provided skip list,
causing silent drops; update the block handling genClientPrefix+"onlyVerbs" so
it first collects onlyVerbs (appending v[0] if present), then check for any
intersection between the existing ret.SkipVerbs (from
genClientPrefix+"skipVerbs") and onlyVerbs and return an error if any verb
appears in both, and only if no conflict compute the new skip list from
SupportedVerbs (or keep the original ret.SkipVerbs when onlyVerbs is empty);
ensure you reference and preserve ret.SkipVerbs, onlyVerbs, SupportedVerbs and
the genClientPrefix+"skipVerbs"/+"onlyVerbs" values during these checks.

In @code-generator/cmd/client-gen/types/helpers.go:
- Around line 84-91: defaultVersion can panic when called with an empty versions
slice because it indexes versionStrings[len(versionStrings)-1]; add a defensive
check in defaultVersion to return a sensible zero value or an error when
len(versions)==0 (for example return Version("") or a defined default) and
document the precondition; ensure you still build the sorted slice using
sortableSliceOfVersions(versionStrings) and reference the
PackageVersion.Version.String() mapping unchanged, and update any callers or add
tests to assert behavior when versions is empty so callers handle the empty-case
consistently.
🧹 Nitpick comments (19)
client-go/examples/README.md (1)

31-31: Simplify the phrase "exact same URI" to reduce wordiness.

The phrase "to the exact same URI here" can be shortened to "to the same URI here" or "to that URI here" for conciseness.

✏️ Proposed wording improvement
-If you started the server with a non-default target, override the socket path with the `NVIDIA_DEVICE_API_TARGET` environment variable to the exact same URI here.
+If you started the server with a non-default target, override the socket path with the `NVIDIA_DEVICE_API_TARGET` environment variable to the same URI here.
client-go/examples/basic-client/README.md (1)

16-16: Simplify the phrase "exact same URI" to reduce wordiness.

The phrase "to the exact same URI here" can be shortened to "to the same URI here" or "to that URI here" for conciseness.

✏️ Proposed wording improvement
-If you started the server with a non-default target, override the socket path with the `NVIDIA_DEVICE_API_TARGET` environment variable to the exact same URI here.
+If you started the server with a non-default target, override the socket path with the `NVIDIA_DEVICE_API_TARGET` environment variable to the same URI here.
api/DEVELOPMENT.md (1)

7-7: Optional: Fix list indentation.

Markdown linting flags the indentation at line 7 (expected 2 spaces, actual 4).

📝 Proposed formatting fix
-    - All Go type definitions must strictly follow the standard [Kubernetes Resource Model](https://github.com/kubernetes/design-proposals-archive/blob/main/architecture/resource-management.md).
+  - All Go type definitions must strictly follow the standard [Kubernetes Resource Model](https://github.com/kubernetes/design-proposals-archive/blob/main/architecture/resource-management.md).
client-go/examples/controller-shim/README.md (1)

9-9: Optional: Fix list indentation.

Markdown linting flags the indentation at line 9 (expected 2 spaces, actual 4).

📝 Proposed formatting fix
-    - _TIP_: Review the `NewInformer` setup in `main.go`. This is the "magic" that allows the standard `controller-runtime` machinery to work over gRPC/UDS without modifying the core controller logic.
+  - _TIP_: Review the `NewInformer` setup in `main.go`. This is the "magic" that allows the standard `controller-runtime` machinery to work over gRPC/UDS without modifying the core controller logic.
code-generator/cmd/client-gen/README.md (1)

47-60: Optional: Add blank lines around the table.

Markdown linting requires blank lines before and after tables for proper rendering.

📝 Proposed formatting fix
 ## Flags
+
 | Flag | Required | Description |
 |------|----------|-------------|
code-generator/cmd/client-gen/generators/scheme/generator_for_scheme.go (1)

24-60: Add package-level godoc + consider import-alias deconfliction

  • New scheme package has no // Package scheme ... doc comment (and exported methods like Namers/Imports/GenerateType are also undocumented). As per coding guidelines, this will trip lint in many setups.
  • groupAlias := strings.ToLower(g.GroupGoNames[...]) risks alias collisions if two groups share the same groupGoName (esp. with overrides). Consider deconflicting (e.g., include version or group package name) or add a validation step up-front.
Proposed minimal doc fix
@@
 package scheme
+
+// Package scheme contains generators for emitting scheme/codec registration
+// for generated clientsets.

Also applies to: 68-89

code-generator/cmd/client-gen/generators/generator_for_type.go (1)

324-341: Use singular parameter names for Create/Update/UpdateStatus templates

These signatures currently use $.type|allLowercasePlural$ *$.type|raw$ (e.g., gpus *GPU), which is confusing for a single object and makes generated code harder to read.

Proposed fix
@@
 var createTemplate = `
 func (c *$.type|allLowercasePlural$) Create(ctx $.context|raw$, $.type|allLowercasePlural$ *$.type|raw$, opts $.CreateOptions|raw$) (*$.type|raw$, error) {
 	return nil, $.fmtErrorf|raw$("Create not implemented for gRPC transport")
 }
 `
@@
 var updateTemplate = `
 func (c *$.type|allLowercasePlural$) Update(ctx $.context|raw$, $.type|allLowercasePlural$ *$.type|raw$, opts $.UpdateOptions|raw$) (*$.type|raw$, error) {
 	return nil, $.fmtErrorf|raw$("Update not implemented for gRPC transport")
 }
 `
@@
 var updateStatusTemplate = `
 func (c *$.type|allLowercasePlural$) UpdateStatus(ctx $.context|raw$, $.type|allLowercasePlural$ *$.type|raw$, opts $.UpdateOptions|raw$) (*$.type|raw$, error) {
 	return nil, $.fmtErrorf|raw$("UpdateStatus not implemented for gRPC transport")
 }
 `
@@
 var createTemplate = `
-func (c *$.type|allLowercasePlural$) Create(ctx $.context|raw$, $.type|allLowercasePlural$ *$.type|raw$, opts $.CreateOptions|raw$) (*$.type|raw$, error) {
+func (c *$.type|allLowercasePlural$) Create(ctx $.context|raw$, obj *$.type|raw$, opts $.CreateOptions|raw$) (*$.type|raw$, error) {
 	return nil, $.fmtErrorf|raw$("Create not implemented for gRPC transport")
 }
 `
@@
 var updateTemplate = `
-func (c *$.type|allLowercasePlural$) Update(ctx $.context|raw$, $.type|allLowercasePlural$ *$.type|raw$, opts $.UpdateOptions|raw$) (*$.type|raw$, error) {
+func (c *$.type|allLowercasePlural$) Update(ctx $.context|raw$, obj *$.type|raw$, opts $.UpdateOptions|raw$) (*$.type|raw$, error) {
 	return nil, $.fmtErrorf|raw$("Update not implemented for gRPC transport")
 }
 `
@@
 var updateStatusTemplate = `
-func (c *$.type|allLowercasePlural$) UpdateStatus(ctx $.context|raw$, $.type|allLowercasePlural$ *$.type|raw$, opts $.UpdateOptions|raw$) (*$.type|raw$, error) {
+func (c *$.type|allLowercasePlural$) UpdateStatus(ctx $.context|raw$, obj *$.type|raw$, opts $.UpdateOptions|raw$) (*$.type|raw$, error) {
 	return nil, $.fmtErrorf|raw$("UpdateStatus not implemented for gRPC transport")
 }
 `
api/device/v1alpha1/converter.go (1)

130-133: Consider returning nil for zero metav1.Time to preserve “unset” semantics

If protobuf timestamp fields are optional, emitting a concrete timestamp for zero-valued metav1.Time{} can turn “missing” into “set to year 1”. If callers rely on “unset”, consider mapping zero to nil.

Proposed fix
@@
 func ToProtobufTimestamp(source metav1.Time) *timestamppb.Timestamp {
+	if source.IsZero() {
+		return nil
+	}
 	return timestamppb.New(source.Time)
 }
client-go/tests/integration/device/v1alpha1/clientset_test.go (3)

122-122: Add type assertion safety check.

The type assertion event.Object.(*devicev1alpha1.GPU) can panic if the object is not a GPU. Use the two-value form to handle unexpected types gracefully.

♻️ Proposed fix
-			gpu := event.Object.(*devicev1alpha1.GPU)
+			gpu, ok := event.Object.(*devicev1alpha1.GPU)
+			if !ok {
+				t.Fatalf("Expected GPU object, got %T", event.Object)
+			}

209-213: Consider blocking on cache start errors.

The cache is started in a goroutine with errors reported via t.Errorf, which won't immediately fail the test. If the cache fails to start, subsequent assertions may produce misleading failures. Consider using a channel or other mechanism to propagate startup errors synchronously, or at minimum use t.Fatalf if startup is critical for the test.


298-316: Refactor lock scope in WatchGpus to prevent potential deadlock.

The RLock is held while iterating and sending to stream.Send() (lines 302-315), which can block if the stream is slow. This creates potential for deadlock or long lock hold times. Consider collecting the snapshot into a slice first, then releasing the lock before sending.

♻️ Proposed fix
 func (m *mockGpuServer) WatchGpus(req *pb.WatchGpusRequest, stream pb.GpuService_WatchGpusServer) error {
 	m.mu.RLock()
-	// Send the initial snapshot (Current state)
+	// Collect the initial snapshot
+	snapshot := make([]*pb.Gpu, 0, len(m.gpus))
 	for _, g := range m.gpus {
+		snapshot = append(snapshot, g)
+	}
+	m.mu.RUnlock()
+
+	// Send the initial snapshot (Current state)
+	for _, g := range snapshot {
 		select {
 		case <-stream.Context().Done():
-			m.mu.RUnlock()
 			return nil
 		default:
 			if err := stream.Send(&pb.WatchGpusResponse{
 				Type:   "ADDED",
 				Object: g,
 			}); err != nil {
-				m.mu.RUnlock()
 				return err
 			}
 		}
 	}
-	m.mu.RUnlock()
 
 	// Continuous watch (Live events)
api/README.md (1)

7-7: Fix markdown list indentation.

The nested list item has 4 spaces of indentation but should have 2 per markdown conventions.

♻️ Proposed fix
 * **`proto/`**: Contains the **Protobuf Message and gRPC Service Definitions**.
-    * *Note:* The `ObjectMeta` and `ListMeta` messages are subsets of `k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta` and `k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta` respectively.
+  * *Note:* The `ObjectMeta` and `ListMeta` messages are subsets of `k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta` and `k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta` respectively.
code-generator/cmd/client-gen/args/gvpackages_test.go (1)

37-123: LGTM! Comprehensive table-driven test.

The test provides good coverage of GV package flag parsing scenarios including empty inputs, multiple groups, defaults, API paths, and import base paths. The use of the standard testing package aligns with project conventions, and the table-driven structure makes it easy to add new test cases.

💡 Optional: Consider more descriptive test naming

While the current name is acceptable, following the pattern TestFunctionName_Scenario_ExpectedBehavior more strictly could improve readability. For example:

-func TestGVPackageFlag(t *testing.T) {
+func TestGVPackageFlag_VariousInputs_ParsesCorrectly(t *testing.T) {

As per coding guidelines for test naming.

code-generator/cmd/client-gen/args/gvtype.go (1)

66-71: Variable types shadows the imported package.

The variable types on line 66 shadows the imported package github.com/nvidia/nvsentinel/code-generator/cmd/client-gen/types. While this works because the package isn't used after this point in the function, it can cause confusion and potential bugs if the function is modified later.

Suggested rename
-		types, ok := (*s.gvToTypes)[gv]
+		typesList, ok := (*s.gvToTypes)[gv]
 		if !ok {
-			types = []string{}
+			typesList = []string{}
 		}
-		types = append(types, typeStr)
-		(*s.gvToTypes)[gv] = types
+		typesList = append(typesList, typeStr)
+		(*s.gvToTypes)[gv] = typesList
code-generator/cmd/client-gen/types/helpers.go (2)

58-79: Consider compiling regex at package level for performance.

The regex regexp.MustCompile("^[0-9]+") is compiled inside Less(), which is called O(n log n) times during sorting. For large version lists, this could be inefficient.

However, since this is copied unmodified from upstream Kubernetes code-generator for compatibility, this may be intentional. Consider adding a comment noting this is kept for upstream parity.


124-127: Remove or document commented-out code.

The commented-out NormalizeGroupVersion function appears to be dead code. Consider removing it or adding a comment explaining why it's preserved.

api/Makefile (1)

27-28: Redundant code-gen execution in all target.

The all target explicitly depends on code-gen, but both test and build also depend on code-gen. This causes code-gen to be evaluated multiple times when running make all.

Consider either:

  1. Removing code-gen from all since it's implicitly run via test and build, or
  2. Removing code-gen as a dependency from test and build if all is the primary entry point.
Option 1: Simplify `all` target
-.PHONY: all
-all: code-gen test build ## Run code generation, compile all code, and execute tests.
+.PHONY: all
+all: test build ## Run code generation, compile all code, and execute tests.
code-generator/cmd/client-gen/generators/generator_for_group.go (1)

218-226: Consider documenting the Discard logger behavior.

The New function creates a client with a discarded logger, which silently drops all log messages. While this is a reasonable default for simple use cases, callers may not realize logging is disabled.

Consider adding a comment to the template noting this behavior, or providing an alternative constructor that accepts a logger parameter.

📝 Suggested documentation improvement
 var newClientForGrpcConnTemplate = `
 // New creates a new $.GroupGoName$$.Version$Client for the given gRPC client connection.
+// Note: This constructor uses a no-op logger. For logging support, use NewForConfigAndClient instead.
 func New(c $.ClientConnInterface|raw$) *$.GroupGoName$$.Version$Client {
 	return &$.GroupGoName$$.Version$Client{
 		conn:   c,
 		logger: $.Discard|raw$(),
 	}
 }
 `
code-generator/kube_codegen.sh (1)

645-653: Debug echo statements should be removed or made conditional.

Lines 647 and 652 contain debug echo statements (echo "input_pkgs=${input_pkgs}" and echo "group_versions=${group_versions}") that will output to stdout during code generation.

These should either be removed for production use or made conditional on a verbose flag.

♻️ Suggested fix
         if grep -E -q '^v[0-9]+((alpha|beta)[0-9]+)?$' <<< "${leaf}"; then
             input_pkgs+=("${pkg}")
-            echo "input_pkgs=${input_pkgs}"
+            if [ "${v}" -ge 2 ]; then
+                echo "input_pkgs=${input_pkgs[@]}"
+            fi

             dir2="$(dirname "${dir}")"
             leaf2="$(basename "${dir2}")"
             group_versions+=("${leaf2}/${leaf}")
-            echo "group_versions=${group_versions}"
+            if [ "${v}" -ge 2 ]; then
+                echo "group_versions=${group_versions[@]}"
+            fi
         fi
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cfd3179 and c24e466.

⛔ Files ignored due to path filters (5)
  • api/device/v1alpha1/zz_generated.goverter.go is excluded by !api/**/zz_generated.*
  • client-go/client/versioned/clientset.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/device_client.go is excluded by !client-go/client/**
  • client-go/client/versioned/typed/device/v1alpha1/gpu.go is excluded by !client-go/client/**
  • code-generator/go.sum is excluded by !**/*.sum
📒 Files selected for processing (39)
  • .versions.yaml
  • api/DEVELOPMENT.md
  • api/Makefile
  • api/README.md
  • api/device/v1alpha1/converter.go
  • api/hack/update-codegen.sh
  • client-go/DEVELOPMENT.md
  • client-go/Makefile
  • client-go/README.md
  • client-go/examples/README.md
  • client-go/examples/basic-client/README.md
  • client-go/examples/controller-shim/README.md
  • client-go/examples/streaming-daemon/README.md
  • client-go/go.mod
  • client-go/hack/update-codegen.sh
  • client-go/tests/integration/device/v1alpha1/clientset_test.go
  • code-generator/CONFIGURATION.md
  • code-generator/LICENSE
  • code-generator/README.md
  • code-generator/cmd/client-gen/README.md
  • code-generator/cmd/client-gen/args/args.go
  • code-generator/cmd/client-gen/args/gvpackages.go
  • code-generator/cmd/client-gen/args/gvpackages_test.go
  • code-generator/cmd/client-gen/args/gvtype.go
  • code-generator/cmd/client-gen/generators/client_generator.go
  • code-generator/cmd/client-gen/generators/generator_for_clientset.go
  • code-generator/cmd/client-gen/generators/generator_for_expansion.go
  • code-generator/cmd/client-gen/generators/generator_for_group.go
  • code-generator/cmd/client-gen/generators/generator_for_type.go
  • code-generator/cmd/client-gen/generators/scheme/generator_for_scheme.go
  • code-generator/cmd/client-gen/generators/util/gvpackages.go
  • code-generator/cmd/client-gen/generators/util/tags.go
  • code-generator/cmd/client-gen/generators/util/tags_test.go
  • code-generator/cmd/client-gen/main.go
  • code-generator/cmd/client-gen/types/helpers.go
  • code-generator/cmd/client-gen/types/helpers_test.go
  • code-generator/cmd/client-gen/types/types.go
  • code-generator/go.mod
  • code-generator/kube_codegen.sh
✅ Files skipped from review due to trivial changes (2)
  • code-generator/CONFIGURATION.md
  • code-generator/README.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • client-go/README.md
  • client-go/go.mod
  • client-go/Makefile
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.go: Follow standard Go conventions with gofmt and golint
Use structured logging via log/slog in Go code
Wrap errors with context using fmt.Errorf("context: %w", err) in Go code
Within retry.RetryOnConflict blocks, return errors without wrapping to preserve retry behavior
Use meaningful variable names such as synced over ok for cache sync checks
Use client-go for Kubernetes API interactions in Go code
Prefer informers over direct API calls for watching Kubernetes resources
Implement proper shutdown handling with context cancellation in Go code
Package-level godoc required for all Go packages
Function comments required for all exported Go functions
Use inline comments for complex logic only in Go code
TODO comments should reference issues in Go code
Extract informer event handler setup into helper methods
Use separate informers for different Kubernetes resource types

Files:

  • code-generator/cmd/client-gen/generators/util/gvpackages.go
  • code-generator/cmd/client-gen/types/helpers_test.go
  • code-generator/cmd/client-gen/args/args.go
  • code-generator/cmd/client-gen/args/gvpackages_test.go
  • code-generator/cmd/client-gen/generators/generator_for_group.go
  • code-generator/cmd/client-gen/types/helpers.go
  • code-generator/cmd/client-gen/types/types.go
  • code-generator/cmd/client-gen/generators/client_generator.go
  • code-generator/cmd/client-gen/generators/scheme/generator_for_scheme.go
  • client-go/tests/integration/device/v1alpha1/clientset_test.go
  • code-generator/cmd/client-gen/args/gvtype.go
  • api/device/v1alpha1/converter.go
  • code-generator/cmd/client-gen/generators/util/tags.go
  • code-generator/cmd/client-gen/generators/generator_for_type.go
  • code-generator/cmd/client-gen/args/gvpackages.go
  • code-generator/cmd/client-gen/generators/generator_for_clientset.go
  • code-generator/cmd/client-gen/generators/util/tags_test.go
  • code-generator/cmd/client-gen/generators/generator_for_expansion.go
  • code-generator/cmd/client-gen/main.go
**/*_test.go

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*_test.go: Use envtest for testing Kubernetes controllers instead of fake clients
Use testify/assert and testify/require for assertions in Go tests
Write table-driven tests when testing multiple scenarios in Go
Name Go tests descriptively using format: TestFunctionName_Scenario_ExpectedBehavior

Files:

  • code-generator/cmd/client-gen/types/helpers_test.go
  • code-generator/cmd/client-gen/args/gvpackages_test.go
  • client-go/tests/integration/device/v1alpha1/clientset_test.go
  • code-generator/cmd/client-gen/generators/util/tags_test.go
**/go.mod

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use go.mod for each service as a separate Go module with semantic import versioning

Files:

  • code-generator/go.mod
🧠 Learnings (18)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code
📚 Learning: 2025-12-22T16:48:13.460Z
Learnt from: pteranodan
Repo: NVIDIA/NVSentinel PR: 607
File: client-go/hack/overlays/client/versioned/typed/device/v1alpha1/gpu.go:15-27
Timestamp: 2025-12-22T16:48:13.460Z
Learning: In the client-go module, files under `hack/overlays/` use the overlay pattern: they are copied into generated code directories and are not compiled standalone. These overlay files may reference types (e.g., `GPUExpansion`) that are generated by Kubernetes code-gen tools and only exist in the final destination. The build excludes overlays via grep patterns like `grep -vE '/hack/overlays/|/examples/'`. Do not flag missing type references in overlay files as compilation errors.

Applied to files:

  • api/hack/update-codegen.sh
  • api/Makefile
  • code-generator/cmd/client-gen/args/args.go
  • code-generator/kube_codegen.sh
  • code-generator/cmd/client-gen/args/gvpackages_test.go
  • code-generator/cmd/client-gen/generators/generator_for_group.go
  • code-generator/cmd/client-gen/types/helpers.go
  • code-generator/cmd/client-gen/types/types.go
  • code-generator/cmd/client-gen/generators/client_generator.go
  • code-generator/cmd/client-gen/generators/scheme/generator_for_scheme.go
  • code-generator/go.mod
  • code-generator/cmd/client-gen/generators/generator_for_type.go
  • client-go/hack/update-codegen.sh
  • code-generator/cmd/client-gen/args/gvpackages.go
  • code-generator/cmd/client-gen/generators/generator_for_clientset.go
  • code-generator/cmd/client-gen/generators/generator_for_expansion.go
  • code-generator/cmd/client-gen/main.go
  • client-go/DEVELOPMENT.md
  • client-go/examples/README.md
  • code-generator/cmd/client-gen/README.md
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use `client-go` for Kubernetes API interactions in Go code

Applied to files:

  • api/hack/update-codegen.sh
  • code-generator/cmd/client-gen/args/args.go
  • .versions.yaml
  • code-generator/kube_codegen.sh
  • code-generator/cmd/client-gen/generators/generator_for_group.go
  • code-generator/cmd/client-gen/types/helpers.go
  • code-generator/cmd/client-gen/types/types.go
  • code-generator/cmd/client-gen/generators/client_generator.go
  • client-go/examples/basic-client/README.md
  • code-generator/go.mod
  • code-generator/cmd/client-gen/generators/util/tags.go
  • code-generator/cmd/client-gen/generators/generator_for_type.go
  • client-go/hack/update-codegen.sh
  • code-generator/cmd/client-gen/generators/generator_for_clientset.go
  • code-generator/cmd/client-gen/generators/util/tags_test.go
  • code-generator/cmd/client-gen/generators/generator_for_expansion.go
  • code-generator/cmd/client-gen/main.go
  • api/DEVELOPMENT.md
  • api/README.md
  • client-go/DEVELOPMENT.md
  • client-go/examples/README.md
  • code-generator/cmd/client-gen/README.md
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Use `envtest` for testing Kubernetes controllers instead of fake clients

Applied to files:

  • code-generator/cmd/client-gen/types/helpers_test.go
  • .versions.yaml
  • code-generator/cmd/client-gen/args/gvpackages_test.go
  • client-go/tests/integration/device/v1alpha1/clientset_test.go
  • code-generator/cmd/client-gen/generators/util/tags_test.go
  • client-go/examples/README.md
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Write table-driven tests when testing multiple scenarios in Go

Applied to files:

  • code-generator/cmd/client-gen/types/helpers_test.go
  • code-generator/cmd/client-gen/args/gvpackages_test.go
  • code-generator/cmd/client-gen/generators/util/tags_test.go
📚 Learning: 2025-12-22T16:16:24.320Z
Learnt from: pteranodan
Repo: NVIDIA/NVSentinel PR: 607
File: client-go/nvgrpc/config_test.go:61-80
Timestamp: 2025-12-22T16:16:24.320Z
Learning: In Go tests across the repository, avoid introducing the testify dependency for simple equality/inequality checks. Use the standard testing package assertions (t.Error, t.Errorf, t.Fatal, etc.) for straightforward checks. Reserve third-party assertion libraries for complex scenarios that require richer diagnostics or expressive matchers.

Applied to files:

  • code-generator/cmd/client-gen/types/helpers_test.go
  • code-generator/cmd/client-gen/args/gvpackages_test.go
  • client-go/tests/integration/device/v1alpha1/clientset_test.go
  • code-generator/cmd/client-gen/generators/util/tags_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to data-models/protobufs/**/*.proto : Define Protocol Buffer messages in `data-models/protobufs/` directory

Applied to files:

  • api/Makefile
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Keep Go dependencies minimal and up-to-date

Applied to files:

  • .versions.yaml
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Follow standard Go conventions with gofmt and golint

Applied to files:

  • .versions.yaml
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*_test.go : Name Go tests descriptively using format: `TestFunctionName_Scenario_ExpectedBehavior`

Applied to files:

  • code-generator/cmd/client-gen/args/gvpackages_test.go
  • code-generator/cmd/client-gen/generators/util/tags_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: All files must include Apache 2.0 license header

Applied to files:

  • code-generator/LICENSE
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use meaningful variable names such as `synced` over `ok` for cache sync checks

Applied to files:

  • client-go/tests/integration/device/v1alpha1/clientset_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Implement proper shutdown handling with context cancellation in Go code

Applied to files:

  • client-go/tests/integration/device/v1alpha1/clientset_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Use separate informers for different Kubernetes resource types

Applied to files:

  • client-go/tests/integration/device/v1alpha1/clientset_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Prefer informers over direct API calls for watching Kubernetes resources

Applied to files:

  • client-go/tests/integration/device/v1alpha1/clientset_test.go
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/go.mod : Use `go.mod` for each service as a separate Go module with semantic import versioning

Applied to files:

  • code-generator/go.mod
📚 Learning: 2026-01-06T21:31:36.113Z
Learnt from: jtschelling
Repo: NVIDIA/NVSentinel PR: 490
File: janitor-provider/go.mod:70-70
Timestamp: 2026-01-06T21:31:36.113Z
Learning: In janitor-provider/go.mod, the dependency github.com/golang-jwt/jwt/v4 v4.5.1 is a transitive dependency from github.com/nebius/gosdk and cannot be directly upgraded without a replace directive or upstream fix in nebius/gosdk.

Applied to files:

  • code-generator/go.mod
📚 Learning: 2025-11-24T22:20:48.152Z
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Applies to **/*.go : Extract informer event handler setup into helper methods

Applied to files:

  • code-generator/go.mod
🧬 Code graph analysis (13)
api/hack/update-codegen.sh (1)
code-generator/kube_codegen.sh (2)
  • kube::codegen::gen_proto_bindings (125-223)
  • kube::codegen::gen_helpers (244-474)
code-generator/cmd/client-gen/args/args.go (3)
code-generator/cmd/client-gen/types/types.go (4)
  • GroupVersions (101-106)
  • GroupVersion (78-81)
  • Group (49-49)
  • Version (32-32)
code-generator/cmd/client-gen/args/gvpackages.go (3)
  • NewGroupVersionsBuilder (122-126)
  • NewGVPackagesValue (71-80)
  • NewInputBasePathValue (44-50)
code-generator/cmd/client-gen/args/gvtype.go (1)
  • NewGVTypesValue (39-48)
code-generator/cmd/client-gen/args/gvpackages_test.go (2)
code-generator/cmd/client-gen/types/types.go (5)
  • GroupVersion (78-81)
  • GroupVersions (101-106)
  • Group (49-49)
  • PackageVersion (72-76)
  • Version (32-32)
code-generator/cmd/client-gen/args/gvpackages.go (3)
  • NewGroupVersionsBuilder (122-126)
  • NewGVPackagesValue (71-80)
  • NewInputBasePathValue (44-50)
code-generator/cmd/client-gen/types/helpers.go (1)
code-generator/cmd/client-gen/types/types.go (7)
  • GroupVersion (78-81)
  • Group (49-49)
  • Version (32-32)
  • PackageVersion (72-76)
  • GroupVersions (101-106)
  • GroupVersionInfo (109-115)
  • GroupInstallPackage (117-120)
code-generator/cmd/client-gen/generators/client_generator.go (4)
code-generator/cmd/client-gen/types/types.go (6)
  • GroupVersion (78-81)
  • ProtobufPackage (123-126)
  • Version (32-32)
  • Group (49-49)
  • GroupVersions (101-106)
  • NewProtobufPackage (128-133)
code-generator/cmd/client-gen/generators/util/tags.go (1)
  • MustParseClientGenTags (189-195)
code-generator/cmd/client-gen/args/args.go (1)
  • Args (34-72)
code-generator/cmd/client-gen/generators/scheme/generator_for_scheme.go (1)
  • GenScheme (42-53)
code-generator/cmd/client-gen/generators/scheme/generator_for_scheme.go (2)
code-generator/cmd/client-gen/types/types.go (4)
  • GroupVersions (101-106)
  • GroupVersion (78-81)
  • Group (49-49)
  • Version (32-32)
code-generator/cmd/client-gen/types/helpers.go (2)
  • ToGroupVersionInfo (94-109)
  • ToGroupInstallPackages (111-122)
client-go/tests/integration/device/v1alpha1/clientset_test.go (1)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
api/device/v1alpha1/converter.go (2)
api/device/v1alpha1/gpu_types.go (4)
  • GPU (55-61)
  • GPUList (67-71)
  • GPUSpec (24-30)
  • GPUStatus (35-45)
api/device/v1alpha1/register.go (1)
  • SchemeGroupVersion (23-23)
code-generator/cmd/client-gen/generators/generator_for_type.go (4)
code-generator/cmd/client-gen/types/types.go (1)
  • ProtobufPackage (123-126)
code-generator/cmd/client-gen/generators/client_generator.go (1)
  • NameSystems (49-113)
code-generator/cmd/client-gen/generators/util/tags.go (3)
  • MustParseClientGenTags (189-195)
  • ParseClientGenTags (199-256)
  • Tags (158-172)
metadata-collector/pkg/writer/writer.go (1)
  • Writer (26-28)
client-go/hack/update-codegen.sh (1)
code-generator/kube_codegen.sh (1)
  • kube::codegen::gen_client (523-730)
code-generator/cmd/client-gen/generators/generator_for_clientset.go (2)
code-generator/cmd/client-gen/types/types.go (4)
  • GroupVersions (101-106)
  • GroupVersion (78-81)
  • Group (49-49)
  • Version (32-32)
code-generator/cmd/client-gen/types/helpers.go (1)
  • ToGroupVersionInfo (94-109)
code-generator/cmd/client-gen/generators/util/tags_test.go (1)
code-generator/cmd/client-gen/generators/util/tags.go (2)
  • Tags (158-172)
  • ParseClientGenTags (199-256)
code-generator/cmd/client-gen/generators/generator_for_expansion.go (1)
metadata-collector/pkg/writer/writer.go (1)
  • Writer (26-28)
🪛 GitHub Actions: Lint and Test
client-go/tests/integration/device/v1alpha1/clientset_test.go

[error] 1-1: license-headers-lint failed. addlicense check reported issues in the file. Run 'make license-headers-lint' to fix license headers.

🪛 LanguageTool
client-go/examples/basic-client/README.md

[style] ~16-~16: ‘exact same’ might be wordy. Consider a shorter alternative.
Context: ...API_TARGET` environment variable to the exact same URI here. ## Expected Output ```text "...

(EN_WORDINESS_PREMIUM_EXACT_SAME)

client-go/examples/streaming-daemon/README.md

[style] ~19-~19: ‘exact same’ might be wordy. Consider a shorter alternative.
Context: ...API_TARGET` environment variable to the exact same URI here. To stop the application, pre...

(EN_WORDINESS_PREMIUM_EXACT_SAME)

client-go/DEVELOPMENT.md

[grammar] ~13-~13: Ensure spelling is correct
Context: ... version/: [Manual] Version injection fFunctionality via ldflags. ## Workflow ### 1. Cod...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

client-go/examples/README.md

[style] ~31-~31: ‘exact same’ might be wordy. Consider a shorter alternative.
Context: ...API_TARGET` environment variable to the exact same URI here.

(EN_WORDINESS_PREMIUM_EXACT_SAME)

client-go/examples/controller-shim/README.md

[style] ~18-~18: ‘exact same’ might be wordy. Consider a shorter alternative.
Context: ...API_TARGET` environment variable to the exact same URI here. To stop the controller, pres...

(EN_WORDINESS_PREMIUM_EXACT_SAME)

🪛 markdownlint-cli2 (0.18.1)
api/DEVELOPMENT.md

7-7: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)

api/README.md

7-7: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)

client-go/examples/controller-shim/README.md

9-9: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)

code-generator/cmd/client-gen/README.md

48-48: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

🔇 Additional comments (34)
code-generator/LICENSE (1)

1-203: Verify license file placement and copyright holder information.

The Apache License 2.0 text is correct and complete. However, ensure that:

  1. License placement: Verify whether code-generator/LICENSE is the intended location, or if NVIDIA prefers a single LICENSE file at the repository root.
  2. Copyright holder: The placeholder Copyright [yyyy] [name of copyright owner] (line 190) should be filled with NVIDIA's actual copyright notice. Confirm this is the correct format and ownership.
code-generator/cmd/client-gen/generators/util/tags_test.go (2)

30-90: LGTM!

The test function follows coding guidelines with a table-driven approach and uses standard testing package assertions. Coverage includes both valid tag parsing scenarios and error cases (invalid formats, conflicts).


92-154: LGTM!

The test function thoroughly covers extension tag parsing with multiple scenarios including valid configurations and comprehensive error handling paths. Follows coding guidelines with table-driven tests and standard testing package assertions.

code-generator/cmd/client-gen/generators/generator_for_expansion.go (3)

35-41: LGTM!

The generator struct follows the standard gengo pattern with appropriate fields for group-level generation.


43-46: LGTM!

The Filter implementation correctly ensures GenerateType is invoked once per group by checking against the first type in the collection.


48-60: LGTM!

The GenerateType method correctly implements idempotent generation—it checks for existing expansion files and only creates stubs when they're missing, preserving user customizations. The template generates the appropriate expansion interface stub.

code-generator/cmd/client-gen/generators/client_generator.go (1)

432-445: Verify internal-version behavior for protobuf import paths

Typed client output directories use gv.Version.NonEmpty() (so internal becomes internalVersion), but protobuf imports are built from version.Version.String() (so internal becomes ""). If you ever generate typed clients for an internal version, this looks like it will import pb from path.Join(protoBase, groupPkgName, "") while writing clients into .../internalversion/.

Please confirm one of:

  • internal versions never generate typed gRPC clients, or
  • protobuf stubs exist at the computed import path for internal versions, or
  • you want internal protobuf packages to use NonEmpty() as well.
code-generator/cmd/client-gen/types/types.go (1)

32-141: LGTM (clean, focused helper types for codegen)

Naming helpers (NonEmpty(), PackageName()) and protobuf import helpers look consistent with their intended use in generators.

code-generator/cmd/client-gen/generators/generator_for_type.go (1)

94-133: The context package import will be present in the generated code and will not be missing.

When the template expands $.context|raw$ on the function signature (line 44 of the watch template), the RawNamer—which is initialized with the ImportTracker—automatically registers the context package import. Therefore, the raw literal context.WithCancel(ctx) on line 50 will compile successfully.

While routing WithCancel through c.Universe.Function() is a valid best-practice for consistency with how other functions like fmtErrorf are handled, it is not required to fix a missing import issue.

Likely an incorrect or invalid review comment.

api/hack/update-codegen.sh (1)

17-35: LGTM! Well-structured code generation script.

The script follows bash best practices with strict error handling (errexit, nounset, pipefail), correctly computes repository paths, and properly invokes the code generation functions from the kube_codegen.sh library. The function calls match the expected signatures for gen_proto_bindings and gen_helpers.

code-generator/cmd/client-gen/generators/util/gvpackages.go (1)

27-36: LGTM! Clean path parsing utility.

The ParsePathGroupVersion function correctly handles path parsing with appropriate edge case handling for paths with 0-2 segments. The logic properly splits group/version paths into their constituent parts using standard library functions.

client-go/DEVELOPMENT.md (1)

1-85: Excellent development documentation.

This guide provides comprehensive coverage of the development workflow, clearly explains the code generation pipeline with a helpful Mermaid diagram, and includes appropriate warnings about not editing generated files. The structure is logical and the examples are practical.

code-generator/cmd/client-gen/main.go (1)

42-78: LGTM! Well-structured code generation entry point.

The main function follows good practices:

  • Proper initialization of logging and argument parsing
  • Deterministic output via sorted input packages (line 59)
  • Argument validation before execution (lines 61-63)
  • Clear error handling with descriptive messages

The TODO comment at line 46 appropriately marks future work without blocking current functionality.

code-generator/cmd/client-gen/args/gvtype.go (1)

39-48: LGTM!

Constructor follows the established Kubernetes code-generator pattern for flag values with panic on invalid defaults, which is appropriate since defaults are compile-time constants.

code-generator/go.mod (1)

5-11: LGTM!

Dependencies are appropriate for a Kubernetes-style code generator. The module follows the coding guideline of using go.mod for each service as a separate Go module.

api/Makefile (1)

55-59: LGTM!

The clean target properly removes both the generated protobuf directory and the zz_generated.*.go files. Using find with -delete is efficient.

code-generator/cmd/client-gen/args/gvpackages.go (1)

128-162: LGTM!

The update() method correctly aggregates versions per group, sorts group names for deterministic output, and properly resets the target slice before building. This ensures consistent code generation across runs.

code-generator/cmd/client-gen/args/args.go (2)

114-132: LGTM!

The Validate() method properly checks all required fields and returns descriptive error messages. Error wrapping follows the coding guideline pattern with fmt.Errorf.


145-152: LGTM!

The mapFlagName helper cleanly provides backward compatibility for the legacy --clientset-path flag by remapping it to --output-pkg. Good use of closure composition.

code-generator/cmd/client-gen/generators/generator_for_clientset.go (3)

76-101: LGTM!

The GenerateType method correctly builds the template context with all required types and functions from the nvgrpc package. The template rendering follows the established Kubernetes code-generator patterns while adapting for gRPC transport. This aligns with the coding guideline to use client-go patterns for Kubernetes API interactions.


124-144: LGTM!

The NewForConfig template correctly implements defensive patterns: nil config check, shallow copy to prevent mutation, and proper error propagation from connection setup.


182-189: LGTM!

The New constructor provides a simple path for users who already have a gRPC connection, which is useful for testing with mock connections or shared connection pools.

code-generator/cmd/client-gen/generators/generator_for_group.go (5)

1-35: License headers and imports look correct.

The file properly attributes the original Kubernetes source and NVIDIA modifications. Imports are appropriate for the code generation task.


37-54: Struct design follows upstream patterns correctly.

The genGroup struct appropriately encapsulates generation state including the single-invocation guard (called) for ensuring GenerateType runs once per group.


56-74: Generator interface methods implemented correctly.

The Filter, Namers, and Imports methods follow the expected generator.Generator interface pattern from gengo.


76-128: GenerateType implementation is sound.

The method correctly:

  • Extracts optional +groupName tag overrides from package comments
  • Handles errors from tag parsing appropriately
  • Iterates over types to generate namespaced vs non-namespaced getters based on client-gen tags
  • Propagates template errors via sw.Error()

Note: The generated code uses logr.Logger (lines 99-100) rather than log/slog. This aligns with Kubernetes client-go conventions where logr is the standard logging facade, so this is appropriate for this context.


130-156: Templates are well-structured and follow Kubernetes patterns.

The interface and client struct templates correctly define the gRPC client surface with ClientConn() accessor and type-specific getters. The namespaced vs non-namespaced getter implementations properly delegate to constructor functions.

code-generator/kube_codegen.sh (7)

22-26: Shell options and script root setup are correct.

The script uses set -o errexit, set -o nounset, and set -o pipefail which are best practices for robust Bash scripts. The KUBE_CODEGEN_ROOT is correctly resolved using portable path handling.


28-34: Version retrieval function works but is fragile with complex YAML.

The get_version function uses simple grep/sed to parse YAML. This works for flat key-value pairs but may fail on nested structures or multi-line values.

Given that .versions.yaml appears to use simple flat structure based on the AI summary (showing entries like goverter: v1.9.3), this is acceptable for the current use case.


94-108: Internal helper functions are well-designed.

The findz and grep wrappers correctly handle cross-repo usage and exclude common non-source directories (.git, _output, vendor). Using null-delimited output (-print0) is the correct approach for safely handling filenames with special characters.


125-223: Proto generation function is well-structured.

The function correctly:

  • Validates input arguments and handles unknown flags
  • Installs required protoc plugins
  • Discovers proto files and cleans existing generated files before regeneration
  • Uses null-delimited processing throughout for safety

668-729: Client generation logic is correctly implemented.

The function properly:

  • Cleans existing generated code before regeneration
  • Builds input arguments array correctly
  • Passes all required flags to client-gen, lister-gen, and informer-gen
  • Conditionally generates watch-related code (listers/informers) only when --with-watch is specified

244-295: Helper generator installation and execution is robust.

The function correctly installs upstream Kubernetes code-gen tools and handles the goverter installation via a temporary module. The trap for cleanup (line 301) ensures the temp directory is removed even on error.


303-310: No action required. Go 1.25 is a valid and current stable version as of January 2026, making the specification in line 305 correct.

Comment on lines +49 to +50
goverter: 'v1.9.3'
kubernetes_code_gen: 'v0.34.1'
Copy link
Contributor

@coderabbitai coderabbitai bot Jan 9, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

goverter v1.9.3 release github jmattheis

💡 Result:

I couldn't find a v1.9.3 release. The project repo is at github.com/jmattheis/goverter [1], and the official install docs list the latest release as v1.9.2. [2]

Sources:

  • GitHub repository: github.com/jmattheis/goverter. [1]
  • Goverter install page (shows "Latest version: v1.9.2"). [2]

🌐 Web query:

kubernetes code-generator v0.34.1 release

💡 Result:

Yes — the k8s module version k8s.io/code-generator v0.34.1 is published and in use (appears in dependency lists and Go modules). Sources showing v0.34.1 include a project go.mod listing and dependency docs. [1][2][3]

Sources:

  • Kubernetes code-generator repository (project page). [1]
  • Example go.mod showing k8s.io/code-generator => v0.34.1 (Volcano mirror). [2]
  • Elastic Cloud on Kubernetes third-party dependencies listing k8s.io/code-generator v0.34.1. [3]

References:
[1] https://github.com/kubernetes/code-generator
[2] https://gitee.com/mirrors/Volcano/blob/master/go.mod
[3] https://www.elastic.co/docs/reference/cloud-on-k8s/third-party-dependencies/3_2_0


🌐 Web query:

goverter security vulnerabilities advisories

💡 Result:

I couldn’t find any published security advisories or CVEs for "goverter" (jmattheis/goverter). Sources checked: the project repository and docs, pkg.go.dev entry, and the GitHub Advisory Database (no matching advisories). [1][2][3]

If you want, I can (a) search additional vulnerability databases (NVD, GitLab, OSV, vendor lists), (b) scan a specific repo version for known-vuln dependencies, or (c) run a quick static/security check on the code—which would you prefer?

Sources:

  • jmattheis/goverter (GitHub). [1]
  • goverter package page (pkg.go.dev). [2]
  • GitHub Advisory Database / browsing advisories (no goverter matches). [3]

🌐 Web query:

kubernetes code-generator security vulnerabilities advisories

💡 Result:

Short answer: I could not find any published security advisories or CVEs that specifically name k8s.io/code-generator (the Kubernetes code-generator tooling) as the vulnerable component. Kubernetes project advisories and CVEs do exist for related components (e.g., kubelet/gitRepo, Image Builder, various k8s modules) — so dependents that vendor or consume code-generator outputs can be affected — but there’s no dedicated code-generator advisory in the official CVE feed or NVD results I found. [1][2][3]

Pointers for ongoing tracking:

  • Kubernetes official CVE feed (watch for new entries). [1]
  • Kubernetes Discuss / Security announcements for advisories such as CVE-2024-10220 (gitRepo/kubelet) and other k8s component advisories. [2][3]
  • GitHub security advisories for the k8s repositories (kubernetes, k8s.io/code-generator, k8s.io/gengo) and the NVD for vendor-assigned CVEs.
  • If you use generated clients/controllers, scan your generated code and upstream k8s module versions and update when k8s modules are bumped (many projects list code-generator in dependency updates). [4][5]

Sources:

  1. Kubernetes official CVE feed / security listing. [k8s.io official CVE feed]. [1]
  2. Kubernetes security announcement / Discuss thread for CVE-2024-10220 (gitRepo kubelet). [2]
  3. External vulnerability writeup summarizing CVE-2024-10220. [3]
  4. Discussion about code-generator/gengo tooling changes and deprecation (impacts to generate-groups). [4]
  5. Package/change logs showing k8s.io/code-generator version bumps in projects (indicative of dependency tracking). [5]

Would you like me to:

  • monitor the official Kubernetes CVE feed and send alerts for any future advisories that mention code-generator, or
  • run a focused search for advisories affecting a specific version you’re using?

Update goverter version to v1.9.2; kubernetes-code-generator v0.34.1 is valid.

The specified goverter version v1.9.3 does not exist. The latest release is v1.9.2. The kubernetes-code-generator v0.34.1 is valid and published. No known security advisories were found for either tool.

🤖 Prompt for AI Agents
In @.versions.yaml around lines 49 - 50, The .versions.yaml entry for goverter
is incorrect—update the goverter key value from 'v1.9.3' to the existing release
'v1.9.2' while leaving kubernetes_code_gen at 'v0.34.1' unchanged; locate the
goverter entry in the file and replace its version string so the key "goverter"
reads 'v1.9.2'.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

v1.9.3 was released on 1/6/26, https://github.com/jmattheis/goverter/releases

Copy link
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

🌐 Web query:

goverter v1.9.3 release january 2026

💡 Result:

I searched but couldn't find any public release notes, download, or repository for "goverter v1.9.3" (January 2026). Do you mean a different name/spelling or can you share a link or more context (project homepage, GitHub/GitLab repo)?


🌐 Web query:

github jmattheis goverter releases latest version

💡 Result:

The latest released version is v1.9.2. [1][2]

Sources:

  • repository README/releases information. [1]
  • official install docs showing go install [email protected]. [2]

@pteranodan, thank you for the clarification!

I've searched multiple times but my results consistently show v1.9.2 as the latest goverter release. However, it's entirely possible that a release from January 6th (just 3 days ago) hasn't been fully indexed by search engines yet.

Could you confirm that you've directly checked the releases page and can see v1.9.3 listed there? If so, then the version specified in .versions.yaml is correct, and the original review comment flagging it as invalid should be disregarded.

For kubernetes_code_gen: 'v0.34.1', that version is confirmed to be valid and published.


🧠 Learnings used
Learnt from: CR
Repo: NVIDIA/NVSentinel PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T22:20:48.152Z
Learning: Keep Go dependencies minimal and up-to-date

- `listers/`: [Generated] Type-safe listers. **Do not edit manually.**
- `informers/`: [Generated] Shared Index Informers. **Do not edit manually.**
- `nvgrpc/`: [Manual] The gRPC transport layer, interceptors, and connection management logic.
- `version/`: [Manual] Version injection fFunctionality via `ldflags`.
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix typo in version description.

There's a typographical error: "fFunctionality" should be "Functionality".

📝 Proposed fix
-- `version/`: [Manual] Version injection fFunctionality via `ldflags`.
+- `version/`: [Manual] Version injection functionality via `ldflags`.
📝 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
- `version/`: [Manual] Version injection fFunctionality via `ldflags`.
- `version/`: [Manual] Version injection functionality via `ldflags`.
🧰 Tools
🪛 LanguageTool

[grammar] ~13-~13: Ensure spelling is correct
Context: ... version/: [Manual] Version injection fFunctionality via ldflags. ## Workflow ### 1. Cod...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🤖 Prompt for AI Agents
In @client-go/DEVELOPMENT.md at line 13, Fix the typo in DEVELOPMENT.md by
updating the description for the `version/` entry: replace "fFunctionality" with
"Functionality" so the line reads "`version/`: [Manual] Version injection
Functionality via `ldflags`."

Comment on lines +19 to +21
**Note:** `sudo` is required because the default socket path is in `/var/run/`. If you started the server with a non-default target, override the socket path with the `NVIDIA_DEVICE_API_TARGET` environment variable to the exact same URI here.

To stop the application, press `Ctrl+C`
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Tighten wording (“exact same”)

Minor readability nit: “the exact same URI” → “the same URI”.

🧰 Tools
🪛 LanguageTool

[style] ~19-~19: ‘exact same’ might be wordy. Consider a shorter alternative.
Context: ...API_TARGET` environment variable to the exact same URI here. To stop the application, pre...

(EN_WORDINESS_PREMIUM_EXACT_SAME)

🤖 Prompt for AI Agents
In @client-go/examples/streaming-daemon/README.md around lines 19 - 21, Change
the phrasing in the README note to tighten wording: replace “the exact same URI”
with “the same URI” in the sentence that tells users to override the socket path
with the NVIDIA_DEVICE_API_TARGET environment variable so it reads “…override
the socket path with the NVIDIA_DEVICE_API_TARGET environment variable to the
same URI here.” to improve readability.

@@ -0,0 +1,336 @@
package v1alpha1_test
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Add missing license header.

The pipeline failure indicates this file is missing the required Apache 2.0 license header. Run make license-headers-lint to add it.

🧰 Tools
🪛 GitHub Actions: Lint and Test

[error] 1-1: license-headers-lint failed. addlicense check reported issues in the file. Run 'make license-headers-lint' to fix license headers.

🤖 Prompt for AI Agents
In @client-go/tests/integration/device/v1alpha1/clientset_test.go at line 1,
This file is missing the required Apache 2.0 license header; add the standard
Apache 2.0 license comment block at the top of the file above the package
declaration in client-go/tests/integration/device/v1alpha1/clientset_test.go,
then run the repository's license linter (make license-headers-lint) to ensure
formatting and compliance.

Comment on lines +44 to +50
func NewInputBasePathValue(builder *groupVersionsBuilder, def string) *inputBasePathValue {
v := &inputBasePathValue{
builder: builder,
}
v.Set(def)
return v
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Ignored error from Set call in constructor.

NewInputBasePathValue calls v.Set(def) but ignores the returned error. If def is an invalid value that causes builder.update() to fail, the error is silently discarded.

Consider panicking on error for consistency with NewGVPackagesValue and NewGVTypesValue, or validate that default values cannot cause errors.

Suggested fix
 func NewInputBasePathValue(builder *groupVersionsBuilder, def string) *inputBasePathValue {
 	v := &inputBasePathValue{
 		builder: builder,
 	}
-	v.Set(def)
+	if err := v.Set(def); err != nil {
+		panic(err)
+	}
 	return v
 }
📝 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 NewInputBasePathValue(builder *groupVersionsBuilder, def string) *inputBasePathValue {
v := &inputBasePathValue{
builder: builder,
}
v.Set(def)
return v
}
func NewInputBasePathValue(builder *groupVersionsBuilder, def string) *inputBasePathValue {
v := &inputBasePathValue{
builder: builder,
}
if err := v.Set(def); err != nil {
panic(err)
}
return v
}
🤖 Prompt for AI Agents
In @code-generator/cmd/client-gen/args/gvpackages.go around lines 44 - 50,
NewInputBasePathValue calls v.Set(def) and ignores its returned error which can
hide builder.update() failures; update the constructor to check the error
returned by inputBasePathValue.Set(def) and panic on non-nil error (consistent
with NewGVPackagesValue/NewGVTypesValue) so invalid default values fail
fast—locate NewInputBasePathValue and inputBasePathValue.Set (which calls
builder.update()) and change the call to capture err and panic with a
descriptive message if err != nil.

Comment on lines +334 to +355
func sanitizePackagePaths(context *generator.Context, args *args.Args) error {
for i := range args.Groups {
pkg := &args.Groups[i]
for j := range pkg.Versions {
ver := &pkg.Versions[j]
input := ver.Package
p := context.Universe[input]
if p == nil || p.Name == "" {
pkgs, err := context.FindPackages(input)
if err != nil {
return fmt.Errorf("can't find input package %q: %w", input, err)
}
p = context.Universe[pkgs[0]]
if p == nil {
return fmt.Errorf("can't find input package %q in universe", input)
}
ver.Package = p.Path
}
}
}
return nil
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Guard against empty FindPackages() results to avoid panic

sanitizePackagePaths assumes pkgs[0] exists when FindPackages(input) succeeds. If it returns an empty slice, this panics.

Proposed fix
@@
 				pkgs, err := context.FindPackages(input)
 				if err != nil {
 					return fmt.Errorf("can't find input package %q: %w", input, err)
 				}
+				if len(pkgs) == 0 {
+					return fmt.Errorf("can't find input package %q: no packages matched", input)
+				}
 				p = context.Universe[pkgs[0]]
 				if p == nil {
 					return fmt.Errorf("can't find input package %q in universe", input)
 				}
📝 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 sanitizePackagePaths(context *generator.Context, args *args.Args) error {
for i := range args.Groups {
pkg := &args.Groups[i]
for j := range pkg.Versions {
ver := &pkg.Versions[j]
input := ver.Package
p := context.Universe[input]
if p == nil || p.Name == "" {
pkgs, err := context.FindPackages(input)
if err != nil {
return fmt.Errorf("can't find input package %q: %w", input, err)
}
p = context.Universe[pkgs[0]]
if p == nil {
return fmt.Errorf("can't find input package %q in universe", input)
}
ver.Package = p.Path
}
}
}
return nil
}
func sanitizePackagePaths(context *generator.Context, args *args.Args) error {
for i := range args.Groups {
pkg := &args.Groups[i]
for j := range pkg.Versions {
ver := &pkg.Versions[j]
input := ver.Package
p := context.Universe[input]
if p == nil || p.Name == "" {
pkgs, err := context.FindPackages(input)
if err != nil {
return fmt.Errorf("can't find input package %q: %w", input, err)
}
if len(pkgs) == 0 {
return fmt.Errorf("can't find input package %q: no packages matched", input)
}
p = context.Universe[pkgs[0]]
if p == nil {
return fmt.Errorf("can't find input package %q in universe", input)
}
ver.Package = p.Path
}
}
}
return nil
}
🤖 Prompt for AI Agents
In @code-generator/cmd/client-gen/generators/client_generator.go around lines
334 - 355, sanitizePackagePaths assumes context.FindPackages(input) returns a
non-empty slice and dereferences pkgs[0], which can panic if the slice is empty;
after calling context.FindPackages(input) in sanitizePackagePaths, check if
len(pkgs) == 0 and return a descriptive error (e.g., "no packages found for
input %q") before accessing pkgs[0], ensuring ver.Package is only set when a
package is actually available.

Comment on lines +145 to +155
// Input returns the input override package path and the type.
func (e *extension) Input() (string, string) {
parts := strings.Split(e.InputTypeOverride, ".")
return parts[len(parts)-1], strings.Join(parts[0:len(parts)-1], ".")
}

// Result returns the result override package path and the type.
func (e *extension) Result() (string, string) {
parts := strings.Split(e.ResultTypeOverride, ".")
return parts[len(parts)-1], strings.Join(parts[0:len(parts)-1], ".")
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

extension.Input() / Result() return order doesn’t match the comment

Both functions claim to return “package path and the type” but currently return (type, package).

Proposed fix (package, type)
@@
 func (e *extension) Input() (string, string) {
 	parts := strings.Split(e.InputTypeOverride, ".")
-	return parts[len(parts)-1], strings.Join(parts[0:len(parts)-1], ".")
+	return strings.Join(parts[0:len(parts)-1], "."), parts[len(parts)-1]
 }
@@
 func (e *extension) Result() (string, string) {
 	parts := strings.Split(e.ResultTypeOverride, ".")
-	return parts[len(parts)-1], strings.Join(parts[0:len(parts)-1], ".")
+	return strings.Join(parts[0:len(parts)-1], "."), parts[len(parts)-1]
 }
📝 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
// Input returns the input override package path and the type.
func (e *extension) Input() (string, string) {
parts := strings.Split(e.InputTypeOverride, ".")
return parts[len(parts)-1], strings.Join(parts[0:len(parts)-1], ".")
}
// Result returns the result override package path and the type.
func (e *extension) Result() (string, string) {
parts := strings.Split(e.ResultTypeOverride, ".")
return parts[len(parts)-1], strings.Join(parts[0:len(parts)-1], ".")
}
// Input returns the input override package path and the type.
func (e *extension) Input() (string, string) {
parts := strings.Split(e.InputTypeOverride, ".")
return strings.Join(parts[0:len(parts)-1], "."), parts[len(parts)-1]
}
// Result returns the result override package path and the type.
func (e *extension) Result() (string, string) {
parts := strings.Split(e.ResultTypeOverride, ".")
return strings.Join(parts[0:len(parts)-1], "."), parts[len(parts)-1]
}
🤖 Prompt for AI Agents
In @code-generator/cmd/client-gen/generators/util/tags.go around lines 145 -
155, The Input() and Result() methods currently return (type, package) but their
comments say they should return (package path, type); fix both by swapping the
return values so they return strings.Join(parts[0:len(parts)-1], ".") first (the
package path) and parts[len(parts)-1] second (the type); do this for
extension.Input() and extension.Result() while preserving the current split
logic and single-segment behavior.

Comment on lines +157 to +186
// Tags represents a genclient configuration for a single type.
type Tags struct {
// +genclient
GenerateClient bool
// +genclient:nonNamespaced
NonNamespaced bool
// +genclient:noStatus
NoStatus bool
// +genclient:noVerbs
NoVerbs bool
// +genclient:skipVerbs=get,update
// +genclient:onlyVerbs=create,delete
SkipVerbs []string
// +genclient:method=UpdateScale,verb=update,subresource=scale,input=Scale,result=Scale
Extensions []extension
}

// HasVerb returns true if we should include the given verb in final client interface and
// generate the function for it.
func (t Tags) HasVerb(verb string) bool {
if len(t.SkipVerbs) == 0 {
return true
}
for _, s := range t.SkipVerbs {
if verb == s {
return false
}
}
return true
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Tags.HasVerb should honor +genclient:noVerbs

Right now NoVerbs doesn’t affect generation unless every generator special-cases it (they don’t in the provided files), so +genclient:noVerbs is effectively ignored.

Proposed fix
@@
 func (t Tags) HasVerb(verb string) bool {
+	if t.NoVerbs {
+		return false
+	}
 	if len(t.SkipVerbs) == 0 {
 		return true
 	}
📝 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
// Tags represents a genclient configuration for a single type.
type Tags struct {
// +genclient
GenerateClient bool
// +genclient:nonNamespaced
NonNamespaced bool
// +genclient:noStatus
NoStatus bool
// +genclient:noVerbs
NoVerbs bool
// +genclient:skipVerbs=get,update
// +genclient:onlyVerbs=create,delete
SkipVerbs []string
// +genclient:method=UpdateScale,verb=update,subresource=scale,input=Scale,result=Scale
Extensions []extension
}
// HasVerb returns true if we should include the given verb in final client interface and
// generate the function for it.
func (t Tags) HasVerb(verb string) bool {
if len(t.SkipVerbs) == 0 {
return true
}
for _, s := range t.SkipVerbs {
if verb == s {
return false
}
}
return true
}
// Tags represents a genclient configuration for a single type.
type Tags struct {
// +genclient
GenerateClient bool
// +genclient:nonNamespaced
NonNamespaced bool
// +genclient:noStatus
NoStatus bool
// +genclient:noVerbs
NoVerbs bool
// +genclient:skipVerbs=get,update
// +genclient:onlyVerbs=create,delete
SkipVerbs []string
// +genclient:method=UpdateScale,verb=update,subresource=scale,input=Scale,result=Scale
Extensions []extension
}
// HasVerb returns true if we should include the given verb in final client interface and
// generate the function for it.
func (t Tags) HasVerb(verb string) bool {
if t.NoVerbs {
return false
}
if len(t.SkipVerbs) == 0 {
return true
}
for _, s := range t.SkipVerbs {
if verb == s {
return false
}
}
return true
}
🤖 Prompt for AI Agents
In @code-generator/cmd/client-gen/generators/util/tags.go around lines 157 -
186, The HasVerb method currently ignores the Tags.NoVerbs flag so
+genclient:noVerbs is ineffective; modify Tags.HasVerb to first check if
t.NoVerbs is true and immediately return false for any verb, otherwise preserve
the existing SkipVerbs logic (iterate t.SkipVerbs and return false if verb
matches, true otherwise). Update the Tags.HasVerb implementation to reference
the NoVerbs field before consulting SkipVerbs so generators honor
+genclient:noVerbs.

Comment on lines +223 to +250
if v, exists := values[genClientPrefix+"skipVerbs"]; exists {
ret.SkipVerbs = strings.Split(v[0], ",")
}
if v, exists := values[genClientPrefix+"onlyVerbs"]; exists || len(onlyVerbs) > 0 {
if len(v) > 0 {
onlyVerbs = append(onlyVerbs, strings.Split(v[0], ",")...)
}
skipVerbs := []string{}
for _, m := range SupportedVerbs {
skip := true
for _, o := range onlyVerbs {
if o == m {
skip = false
break
}
}
// Check for conflicts
for _, v := range skipVerbs {
if v == m {
return ret, fmt.Errorf("verb %q used both in genclient:skipVerbs and genclient:onlyVerbs", v)
}
}
if skip {
skipVerbs = append(skipVerbs, m)
}
}
ret.SkipVerbs = skipVerbs
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix skipVerbs vs onlyVerbs conflict handling (and avoid silently dropping skipVerbs)

If +genclient:skipVerbs=... is set and +genclient:onlyVerbs=... is also set (or implied via readonly), current logic overwrites ret.SkipVerbs and the “conflict” check doesn’t actually compare against the user-provided skip list.

Proposed fix (fail fast on conflicts)
@@
 	if v, exists := values[genClientPrefix+"skipVerbs"]; exists {
 		ret.SkipVerbs = strings.Split(v[0], ",")
 	}
 	if v, exists := values[genClientPrefix+"onlyVerbs"]; exists || len(onlyVerbs) > 0 {
+		if len(ret.SkipVerbs) > 0 {
+			return ret, fmt.Errorf("cannot use both genclient:skipVerbs and genclient:onlyVerbs")
+		}
 		if len(v) > 0 {
 			onlyVerbs = append(onlyVerbs, strings.Split(v[0], ",")...)
 		}
 		skipVerbs := []string{}
 		for _, m := range SupportedVerbs {
 			skip := true
 			for _, o := range onlyVerbs {
 				if o == m {
 					skip = false
 					break
 				}
 			}
-			// Check for conflicts
-			for _, v := range skipVerbs {
-				if v == m {
-					return ret, fmt.Errorf("verb %q used both in genclient:skipVerbs and genclient:onlyVerbs", v)
-				}
-			}
 			if skip {
 				skipVerbs = append(skipVerbs, m)
 			}
 		}
 		ret.SkipVerbs = skipVerbs
 	}
🤖 Prompt for AI Agents
In @code-generator/cmd/client-gen/generators/util/tags.go around lines 223 -
250, The conflict logic currently overwrites ret.SkipVerbs when onlyVerbs is
specified and never compares the user-provided skip list, causing silent drops;
update the block handling genClientPrefix+"onlyVerbs" so it first collects
onlyVerbs (appending v[0] if present), then check for any intersection between
the existing ret.SkipVerbs (from genClientPrefix+"skipVerbs") and onlyVerbs and
return an error if any verb appears in both, and only if no conflict compute the
new skip list from SupportedVerbs (or keep the original ret.SkipVerbs when
onlyVerbs is empty); ensure you reference and preserve ret.SkipVerbs, onlyVerbs,
SupportedVerbs and the genClientPrefix+"skipVerbs"/+"onlyVerbs" values during
these checks.

Comment on lines +84 to +91
func defaultVersion(versions []PackageVersion) Version {
var versionStrings []string
for _, version := range versions {
versionStrings = append(versionStrings, version.Version.String())
}
sort.Sort(sortableSliceOfVersions(versionStrings))
return Version(versionStrings[len(versionStrings)-1])
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Potential panic if versions is empty.

defaultVersion accesses versionStrings[len(versionStrings)-1] without checking if the slice is empty. If called with an empty versions slice, this will panic with an index out of range error.

Since this is copied from upstream for compatibility, consider adding a defensive check or documenting the precondition that versions must be non-empty.

🤖 Prompt for AI Agents
In @code-generator/cmd/client-gen/types/helpers.go around lines 84 - 91,
defaultVersion can panic when called with an empty versions slice because it
indexes versionStrings[len(versionStrings)-1]; add a defensive check in
defaultVersion to return a sensible zero value or an error when len(versions)==0
(for example return Version("") or a defined default) and document the
precondition; ensure you still build the sorted slice using
sortableSliceOfVersions(versionStrings) and reference the
PackageVersion.Version.String() mapping unchanged, and update any callers or add
tests to assert behavior when versions is empty so callers handle the empty-case
consistently.

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.

2 participants