Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .golangci-kal.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ linters:
policy: SuggestFix # SuggestFix | Warn # The policy for pointers in optional fields. Defaults to `SuggestFix`.
omitempty:
policy: SuggestFix # SuggestFix | Warn | Ignore # The policy for omitempty in optional fields. Defaults to `SuggestFix`.
omitzero:
policy: Forbid # Enforce the `omitempty` route with a pointer for all optional structs.
exclusions:
generated: strict
paths:
Expand Down
191 changes: 103 additions & 88 deletions api/v1/inferencepool_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,18 @@
// +optional
metav1.ObjectMeta `json:"metadata,omitempty"`

// Spec defines the desired state of the InferencePool.
//
// +required
Spec InferencePoolSpec `json:"spec,omitzero"`

// Status defines the observed state of InferencePool.
// Status defines the observed state of the InferencePool.
//
// +kubebuilder:default={parent: {{parentRef: {kind: "Status", name: "default"}, conditions: {{type: "Accepted", status: "Unknown", reason: "Pending", message: "Waiting for controller", lastTransitionTime: "1970-01-01T00:00:00Z"}}}}}
// +optional
Status InferencePoolStatus `json:"status,omitzero"`
Status InferencePoolStatus `json:"status,omitempty"`

Check failure on line 46 in api/v1/inferencepool_types.go

View workflow job for this annotation

GitHub Actions / kube-api-lint

optionalfields: field Status has a valid zero value ({}), but the validation is not complete (e.g. min properties/adding required fields). The field should be a pointer to allow the zero value to be set. If the zero value is not a valid use case, complete the validation and remove the pointer. (kubeapilinter)
}

// InferencePoolList contains a list of InferencePool.
// InferencePoolList contains a list of InferencePools.
//
// +kubebuilder:object:root=true
type InferencePoolList struct {
Expand All @@ -54,7 +55,7 @@
Items []InferencePool `json:"items"`
}

// InferencePoolSpec defines the desired state of InferencePool
// InferencePoolSpec defines the desired state of the InferencePool.
type InferencePoolSpec struct {
// Selector determines which Pods are members of this inference pool.
// It matches Pods by their labels only within the same namespace; cross-namespace
Expand All @@ -65,19 +66,22 @@
// this configuration into a Service resource.
//
// +required
Selector LabelSelector `json:"selector,omitempty,omitzero"`
Selector LabelSelector `json:"selector,omitzero"`

Check failure on line 69 in api/v1/inferencepool_types.go

View workflow job for this annotation

GitHub Actions / kube-api-lint

requiredfields: field Selector has a valid zero value ({"matchLabels": {}}) and should be a pointer. (kubeapilinter)

// TargetPorts defines a list of ports that are exposed by this InferencePool.
// Currently, the list may only include a single port definition.
//
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=1
// +listType=atomic
// +required
TargetPorts []Port `json:"targetPorts,omitempty"`
TargetPorts []Port `json:"targetPorts,omitzero"`

Check failure on line 78 in api/v1/inferencepool_types.go

View workflow job for this annotation

GitHub Actions / kube-api-lint

requiredfields: field TargetPorts should have the omitempty tag. (kubeapilinter)

// EndpointPickerRef configures an endpoint picker as an extension service.
// EndpointPickerRef is a reference to the Endpoint Picker extension and its
// associated configuration.
//
// +required
EndpointPickerRef EndpointPickerRef `json:"endpointPickerRef,omitempty,omitzero"`
EndpointPickerRef EndpointPickerRef `json:"endpointPickerRef,omitzero"`
}

// Port defines the network port that will be exposed by this InferencePool.
Expand All @@ -86,21 +90,22 @@
// The number must be in the range 1 to 65535.
//
// +required
Number PortNumber `json:"number,omitempty"`
Number PortNumber `json:"number,omitzero"`

Check failure on line 93 in api/v1/inferencepool_types.go

View workflow job for this annotation

GitHub Actions / kube-api-lint

requiredfields: field Number should have the omitempty tag. (kubeapilinter)
}

// Extension specifies how to configure an extension that runs the endpoint picker.
// EndpointPickerRef specifies a reference to an Endpoint Picker extension and its
// associated configuration.
type EndpointPickerRef struct {
// Group is the group of the referent.
// The default value is "", representing the Core API group.
// Group is the group of the referent API object. When unspecified, the default value
// is "", representing the Core API group.
//
// +optional
// +kubebuilder:default=""
Group *Group `json:"group,omitempty"`

// Kind is the Kubernetes resource kind of the referent.
//
// Required if the referent is ambiguous(e.g. service with one port is unambiguous).
// Required if the referent is ambiguous, e.g. service with multiple ports.
//
// Defaults to "Service" when not specified.
//
Expand All @@ -112,100 +117,105 @@
//
// +optional
// +kubebuilder:default=Service
Kind Kind `json:"kind,omitempty"`
Kind *Kind `json:"kind,omitempty"`

Check failure on line 120 in api/v1/inferencepool_types.go

View workflow job for this annotation

GitHub Actions / kube-api-lint

optionalfields: field Kind does not allow the zero value. The field does not need to be a pointer. (kubeapilinter)

// Name is the name of the referent.
// Name is the name of the referent API object.
//
// +required
Name ObjectName `json:"name,omitempty"`
Name ObjectName `json:"name,omitzero"`

Check failure on line 125 in api/v1/inferencepool_types.go

View workflow job for this annotation

GitHub Actions / kube-api-lint

requiredfields: field Name should have the omitempty tag. (kubeapilinter)

// The port number on the service running the extension. When unspecified,
// implementations SHOULD infer a default value of 9002 when the Kind is
// Service.
// PortNumber is the port number of the Endpoint Picker extension service. When unspecified,
// implementations SHOULD infer a default value of 9002 when the kind field is "Service" or
// unspecified (defaults to "Service").
//
// +optional
//nolint:kubeapilinter // ignore kubeapilinter here as we want to use pointer here as 0 usually means all ports.
PortNumber *PortNumber `json:"portNumber,omitempty"`

Check failure on line 132 in api/v1/inferencepool_types.go

View workflow job for this annotation

GitHub Actions / kube-api-lint

optionalfields: field PortNumber does not allow the zero value. The field does not need to be a pointer. (kubeapilinter)

// Configures how the gateway handles the case when the extension is not responsive.
// Defaults to failClose.
// FailureMode configures how the parent handles the case when the Endpoint Picker extension
// is non-responsive. When unspecified, defaults to "FailClose".
//
// +optional
// +kubebuilder:default="FailClose"
FailureMode ExtensionFailureMode `json:"failureMode,omitempty"`
FailureMode *EndpointPickerFailureMode `json:"failureMode,omitempty"`

Check failure on line 139 in api/v1/inferencepool_types.go

View workflow job for this annotation

GitHub Actions / kube-api-lint

optionalfields: field FailureMode does not allow the zero value. The field does not need to be a pointer. (kubeapilinter)
}

// ExtensionFailureMode defines the options for how the gateway handles the case when the extension is not
// responsive.
// EndpointPickerFailureMode defines the options for how the parent handles the case when the
// Endpoint Picker extension is non-responsive.
//
// +kubebuilder:validation:Enum=FailOpen;FailClose
type ExtensionFailureMode string
type EndpointPickerFailureMode string

const (
// FailOpen specifies that the proxy should forward the request to an endpoint of its picking when the Endpoint Picker fails.
FailOpen ExtensionFailureMode = "FailOpen"
// FailClose specifies that the proxy should drop the request when the Endpoint Picker fails.
FailClose ExtensionFailureMode = "FailClose"
// EndpointPickerFailOpen specifies that the parent should forward the request to an endpoint
// of its picking when the Endpoint Picker extension fails.
EndpointPickerFailOpen EndpointPickerFailureMode = "FailOpen"
// EndpointPickerFailClose specifies that the parent should drop the request when the Endpoint
// Picker extension fails.
EndpointPickerFailClose EndpointPickerFailureMode = "FailClose"
)

// InferencePoolStatus defines the observed state of InferencePool.
// +kubebuilder:validation:MinProperties=1
Copy link
Contributor Author

@danehans danehans Aug 21, 2025

Choose a reason for hiding this comment

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

I removed +kubebuilder:validation:MinProperties=1 since the struct contains only one field, and the field is optional.

// InferencePoolStatus defines the observed state of the InferencePool.
type InferencePoolStatus struct {
// Parents is a list of parent resources (usually Gateways) that are
// associated with the InferencePool, and the status of the InferencePool with respect to
// each parent.
// Parents is a list of parent resources, typically Gateways, that are associated with
// the InferencePool, and the status of the InferencePool with respect to each parent.
//
// A maximum of 32 Gateways will be represented in this list. When the list contains
// `kind: Status, name: default`, it indicates that the InferencePool is not
// associated with any Gateway and a controller must perform the following:
// A controller that manages the InferencePool, must add an entry for each parent it manages
// and remove the parent entry when the controller no longer considers the InferencePool to
// be associated with that parent.
//
// - Remove the parent when setting the "Accepted" condition.
// - Add the parent when the controller will no longer manage the InferencePool
// and no other parents exist.
// A maximum of 32 parents will be represented in this list. When the list is empty,
// it indicates that the InferencePool is not associated with any parents.
//
// +kubebuilder:validation:MaxItems=32
// +optional
// +listType=atomic
Parents []PoolStatus `json:"parent,omitempty"`
Parents []ParentStatus `json:"parents,omitempty"`
}

// PoolStatus defines the observed state of InferencePool from a Gateway.
type PoolStatus struct {
// Conditions track the state of the InferencePool.
// ParentStatus defines the observed state of InferencePool from a Parent, i.e. Gateway.
type ParentStatus struct {
// Conditions is a list of status conditions that provide information about the observed
// state of the InferencePool. This field is required to be set by the controller that
// manages the InferencePool.
//
// Known condition types are:
// Supported condition types are:
//
// * "Accepted"
// * "ResolvedRefs"
//
// +optional
// +listType=map
// +listMapKey=type
// +patchStrategy=merge
// +patchMergeKey=type
// +kubebuilder:validation:MaxItems=8
// +kubebuilder:default={{type: "Accepted", status: "Unknown", reason:"Pending", message:"Waiting for controller", lastTransitionTime: "1970-01-01T00:00:00Z"}}
Conditions []metav1.Condition `json:"conditions,omitempty"`

Check failure on line 192 in api/v1/inferencepool_types.go

View workflow job for this annotation

GitHub Actions / kube-api-lint

conditions: Conditions field has the following additional markers: patchStrategy=merge, patchMergeKey=type (kubeapilinter)

// GatewayRef indicates the gateway that observed state of InferencePool.
// ParentRef is used to identify the parent resource that this status
// is associated with. It is used to match the InferencePool with the parent
// resource, such as a Gateway.
//
// +required
GatewayRef ParentGatewayReference `json:"parentRef,omitzero"`
ParentRef ParentReference `json:"parentRef,omitzero"`
}

// InferencePoolConditionType is a type of condition for the InferencePool
// InferencePoolConditionType is a type of status condition for the InferencePool.
type InferencePoolConditionType string

// InferencePoolReason is the reason for a given InferencePoolConditionType
// InferencePoolReason is the reason for a type of InferencePool status condition.
type InferencePoolReason string

const (
// This condition indicates whether the InferencePool has been accepted or rejected
// by a Gateway, and why.
// InferencePoolConditionAccepted is a type of condition that indicates whether
// the InferencePool has been accepted or rejected by a Parent, and why.
//
// Possible reasons for this condition to be True are:
//
// * "Accepted"
// * "SupportedByParent"
Copy link
Member

Choose a reason for hiding this comment

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

We've always used Accepted as the only positive polarity reason for a resource to be Accepted in Gateway API, recommend keeping that here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have always found the Accepted reason to be unusual. The condition type is Accepted, and when being set to False, the reason is "NotSupportedByParent". The opposite should be set when Accepted: True, e.g., "SupportedByParent".

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@robscott While on the topic of status condition reasons, PTAL at the following:

	// This reason is used with the "Accepted" when a controller has not yet
	// reconciled the InferencePool.
	InferencePoolReasonPending InferencePoolReason = "Pending"

Now that the default status condition has been removed, I question whether this reason is still applicable. If a controller has not yet reconciled the resource, something else is required to set Accepted: Unknown with Reason: Pending.

Copy link
Member

Choose a reason for hiding this comment

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

Now that the default status condition has been removed, I question whether this reason is still applicable.

+1, let's remove it.

I have always found the Accepted reason to be unusual. The condition type is Accepted, and when being set to False, the reason is "NotSupportedByParent".

The problem is when you have multiple reasons that a condition could be false. Take HTTPRoute for an example. To follow your example, the positive condition would be something like "AllowedByListenersAndHasMatchingHostnameAndParentAndNoUnsupportedValues".

I think the odds that we add more reasons to be false in the future are quite here, so I'd rather stick with a simpler reason for the positive state here and follow what GW API has done.

//
// Possible reasons for this condition to be False are:
//
// * "NotSupportedByGateway"
// * "Accepted"
// * "HTTPRouteNotAccepted"
//
// Possible reasons for this condition to be Unknown are:
Expand All @@ -216,28 +226,26 @@
// prefer to use the reasons listed above to improve interoperability.
InferencePoolConditionAccepted InferencePoolConditionType = "Accepted"

// This reason is used with the "Accepted" condition when the InferencePool has been
// accepted by the Gateway.
// InferencePoolReasonAccepted is a reason used with the "Accepted" condition
// when the InferencePool is accepted by a Parent because the Parent supports
// InferencePool as a backend.
InferencePoolReasonAccepted InferencePoolReason = "Accepted"

// This reason is used with the "Accepted" condition when the InferencePool
// has not been accepted by a Gateway because the Gateway does not support
// InferencePool as a backend.
InferencePoolReasonNotSupportedByGateway InferencePoolReason = "NotSupportedByGateway"
// InferencePoolReasonNotSupportedByParent is a reason used with the "Accepted"
// condition when the InferencePool has not been accepted by a Parent because
// the Parent does not support InferencePool as a backend.
InferencePoolReasonNotSupportedByParent InferencePoolReason = "NotSupportedByParent"

// This reason is used with the "Accepted" condition when the InferencePool is
// referenced by an HTTPRoute that has been rejected by the Gateway. The user
// should inspect the status of the referring HTTPRoute for the specific reason.
// InferencePoolReasonHTTPRouteNotAccepted is an optional reason used with the
// "Accepted" condition when the InferencePool is referenced by an HTTPRoute that
// has been rejected by the Parent. The user should inspect the status of the
// referring HTTPRoute for the specific reason.
InferencePoolReasonHTTPRouteNotAccepted InferencePoolReason = "HTTPRouteNotAccepted"

// This reason is used with the "Accepted" when a controller has not yet
// reconciled the InferencePool.
InferencePoolReasonPending InferencePoolReason = "Pending"
)

const (
// This condition indicates whether the controller was able to resolve all
// the object references for the InferencePool.
// InferencePoolConditionResolvedRefs is a type of condition that indicates whether
// the controller was able to resolve all the object references for the InferencePool.
//
// Possible reasons for this condition to be True are:
//
Expand All @@ -251,39 +259,46 @@
// prefer to use the reasons listed above to improve interoperability.
InferencePoolConditionResolvedRefs InferencePoolConditionType = "ResolvedRefs"

// This reason is used with the "ResolvedRefs" condition when the condition
// is true.
// InferencePoolReasonResolvedRefs is a reason used with the "ResolvedRefs"
// condition when the condition is true.
InferencePoolReasonResolvedRefs InferencePoolReason = "ResolvedRefs"

// This reason is used with the "ResolvedRefs" condition when the
// Extension is invalid in some way. This can include an unsupported kind
// or API group, or a reference to a resource that can not be found.
// InferencePoolReasonInvalidExtensionRef is a reason used with the "ResolvedRefs"
// condition when the Extension is invalid in some way. This can include an
// unsupported kind or API group, or a reference to a resource that cannot be found.
InferencePoolReasonInvalidExtensionRef InferencePoolReason = "InvalidExtensionRef"
)

// ParentGatewayReference identifies an API object including its namespace,
// defaulting to Gateway.
type ParentGatewayReference struct {
// Group is the group of the referent.
// ParentReference identifies an API object. It is used to associate the InferencePool with a
// parent resource, such as a Gateway.
type ParentReference struct {
// Group is the group of the referent API object. When unspecified, the referent is assumed
// to be in the "gateway.networking.k8s.io" API group.
//
// +optional
// +kubebuilder:default="gateway.networking.k8s.io"
Group *Group `json:"group,omitempty"`

// Kind is kind of the referent. For example "Gateway".
// Kind is the kind of the referent API object. When unspecified, the referent is assumed
// to be a "Gateway" kind.
//
// +optional
// +kubebuilder:default=Gateway
Kind Kind `json:"kind,omitempty"`
Kind *Kind `json:"kind,omitempty"`

Check failure on line 287 in api/v1/inferencepool_types.go

View workflow job for this annotation

GitHub Actions / kube-api-lint

optionalfields: field Kind does not allow the zero value. The field does not need to be a pointer. (kubeapilinter)

// Name is the name of the referent.
// Name is the name of the referent API object.
//
// +required
Name ObjectName `json:"name,omitempty"`
Name ObjectName `json:"name,omitzero"`

// Namespace is the namespace of the referent. If not present,
// the namespace of the referent is assumed to be the same as
// the namespace of the referring object.
// Namespace is the namespace of the referenced object. When unspecified, the local
// namespace is inferred.
//
// Note that when a namespace different than the local namespace is specified,
// a ReferenceGrant object is required in the referent namespace to allow that
// namespace's owner to accept the reference. See the ReferenceGrant
// documentation for details: https://gateway-api.sigs.k8s.io/api-types/referencegrant/
//
// +optional
Namespace Namespace `json:"namespace,omitempty"`
Namespace *Namespace `json:"namespace,omitempty"`
}
5 changes: 3 additions & 2 deletions api/v1/shared_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,12 @@ type LabelValue string
// LabelSelector defines a query for resources based on their labels.
// This simplified version uses only the matchLabels field.
type LabelSelector struct {
// matchLabels contains a set of required {key,value} pairs.
// MatchLabels contains a set of required {key,value} pairs.
// An object must match every label in this map to be selected.
// The matching logic is an AND operation on all entries.
//
// +required
// +kubebuilder:validation:MinItems=1
// +kubebuilder:validation:MaxItems=64
MatchLabels map[LabelKey]LabelValue `json:"matchLabels,omitempty" protobuf:"bytes,1,rep,name=matchLabels"`
MatchLabels map[LabelKey]LabelValue `json:"matchLabels,omitzero"`
}
Loading