Skip to content

Commit bc242de

Browse files
authored
Enable kubeapilinter for GIE APIs (#1366)
* Enable kubeapilinter github action * Fix findings on stable APIs * Fix findings after rebase
1 parent b11a1f4 commit bc242de

File tree

12 files changed

+150
-77
lines changed

12 files changed

+150
-77
lines changed

.custom-gcl.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
version: v2.3.1
2+
name: golangci-kube-api-linter
3+
destination: ./bin
4+
plugins:
5+
- module: 'sigs.k8s.io/kube-api-linter'
6+
version: 'v0.0.0-20250808120943-48643eb2563d' # Pin to a commit while there's no tag

.github/workflows/kal.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: PR golangci-lint
2+
3+
on:
4+
pull_request:
5+
types: [opened, edited, synchronize, reopened]
6+
7+
# Remove all permissions from GITHUB_TOKEN except metadata.
8+
permissions: {}
9+
10+
jobs:
11+
golangci:
12+
name: kube-api-lint
13+
runs-on: ubuntu-latest
14+
strategy:
15+
fail-fast: false
16+
steps:
17+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2
18+
name: Checkout code
19+
with:
20+
persist-credentials: false
21+
- name: Set up Go
22+
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # tag=v5.5.0
23+
- name: Install Golang CI Lint
24+
run: go install github.com/golangci/golangci-lint/v2/cmd/[email protected]
25+
- name: Build KAL
26+
run: golangci-lint custom
27+
- name: run api linter
28+
run: ./bin/golangci-kube-api-linter run -c ./.golangci-kal.yml ./...

.golangci-kal.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
version: "2"
2+
linters:
3+
default: none
4+
enable:
5+
- kubeapilinter
6+
settings:
7+
custom:
8+
kubeapilinter:
9+
type: module
10+
description: Kube API LInter lints Kube like APIs based on API conventions and best practices.
11+
settings:
12+
linters:
13+
enable:
14+
- "*"
15+
disable:
16+
- "commentstart"
17+
lintersConfig:
18+
conflictingmarkers:
19+
conflicts:
20+
- name: "default_vs_required"
21+
sets:
22+
- ["default", "kubebuilder:default"]
23+
- ["required", "kubebuilder:validation:Required", "k8s:required"]
24+
description: "A field with a default value cannot be required"
25+
conditions:
26+
isFirstField: Warn # Require conditions to be the first field in the status struct.
27+
usePatchStrategy: Forbid # Forbid patchStrategy markers on the Conditions field.
28+
useProtobuf: Forbid # We don't use protobuf, so protobuf tags are not required.
29+
optionalfields:
30+
pointers:
31+
preference: WhenRequired # Always | WhenRequired # Whether to always require pointers, or only when required. Defaults to `Always`.
32+
policy: SuggestFix # SuggestFix | Warn # The policy for pointers in optional fields. Defaults to `SuggestFix`.
33+
omitempty:
34+
policy: SuggestFix # SuggestFix | Warn | Ignore # The policy for omitempty in optional fields. Defaults to `SuggestFix`.
35+
exclusions:
36+
generated: strict
37+
paths:
38+
- conformance/
39+
paths-except:
40+
- api/
41+
issues:
42+
max-issues-per-linter: 0
43+
max-same-issues: 0
44+
run:
45+
timeout: 5m
46+
tests: false

api/v1/inferencepool_types.go

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,19 @@ import (
2929
// +kubebuilder:storageversion
3030
// +genclient
3131
type InferencePool struct {
32-
metav1.TypeMeta `json:",inline"`
32+
metav1.TypeMeta `json:",inline"`
33+
34+
// +optional
3335
metav1.ObjectMeta `json:"metadata,omitempty"`
3436

35-
Spec InferencePoolSpec `json:"spec,omitempty"`
37+
// +required
38+
Spec InferencePoolSpec `json:"spec,omitzero"`
3639

3740
// Status defines the observed state of InferencePool.
3841
//
3942
// +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"}}}}}
40-
Status InferencePoolStatus `json:"status,omitempty"`
43+
// +optional
44+
Status InferencePoolStatus `json:"status,omitzero"`
4145
}
4246

4347
// InferencePoolList contains a list of InferencePool.
@@ -59,19 +63,20 @@ type InferencePoolSpec struct {
5963
// with Kubernetes Service selectors, as some implementations may translate
6064
// this configuration into a Service resource.
6165
//
62-
// +kubebuilder:validation:Required
63-
Selector LabelSelector `json:"selector"`
66+
// +required
67+
Selector LabelSelector `json:"selector,omitempty,omitzero"`
6468

6569
// TargetPortNumber defines the port number to access the selected model server Pods.
6670
// The number must be in the range 1 to 65535.
6771
//
6872
// +kubebuilder:validation:Minimum=1
6973
// +kubebuilder:validation:Maximum=65535
70-
// +kubebuilder:validation:Required
71-
TargetPortNumber int32 `json:"targetPortNumber"`
74+
// +required
75+
TargetPortNumber int32 `json:"targetPortNumber,omitempty"`
7276

7377
// Extension configures an endpoint picker as an extension service.
74-
ExtensionRef *Extension `json:"extensionRef,omitempty"`
78+
// +optional
79+
ExtensionRef Extension `json:"extensionRef,omitempty,omitzero"`
7580
}
7681

7782
// Extension specifies how to configure an extension that runs the endpoint picker.
@@ -95,26 +100,26 @@ type Extension struct {
95100
//
96101
// +optional
97102
// +kubebuilder:default=Service
98-
Kind *Kind `json:"kind,omitempty"`
103+
Kind Kind `json:"kind,omitempty"`
99104

100105
// Name is the name of the referent.
101106
//
102-
// +kubebuilder:validation:Required
103-
Name ObjectName `json:"name"`
107+
// +required
108+
Name ObjectName `json:"name,omitempty"`
104109

105110
// The port number on the service running the extension. When unspecified,
106111
// implementations SHOULD infer a default value of 9002 when the Kind is
107112
// Service.
108113
//
109114
// +optional
110-
PortNumber *PortNumber `json:"portNumber,omitempty"`
115+
PortNumber PortNumber `json:"portNumber,omitempty"`
111116

112117
// Configures how the gateway handles the case when the extension is not responsive.
113118
// Defaults to failClose.
114119
//
115120
// +optional
116121
// +kubebuilder:default="FailClose"
117-
FailureMode *ExtensionFailureMode `json:"failureMode"`
122+
FailureMode ExtensionFailureMode `json:"failureMode,omitempty"`
118123
}
119124

120125
// ExtensionFailureMode defines the options for how the gateway handles the case when the extension is not
@@ -130,6 +135,7 @@ const (
130135
)
131136

132137
// InferencePoolStatus defines the observed state of InferencePool.
138+
// +kubebuilder:validation:MinProperties=1
133139
type InferencePoolStatus struct {
134140
// Parents is a list of parent resources (usually Gateways) that are
135141
// associated with the InferencePool, and the status of the InferencePool with respect to
@@ -144,14 +150,13 @@ type InferencePoolStatus struct {
144150
// and no other parents exist.
145151
//
146152
// +kubebuilder:validation:MaxItems=32
153+
// +optional
154+
// +listType=atomic
147155
Parents []PoolStatus `json:"parent,omitempty"`
148156
}
149157

150158
// PoolStatus defines the observed state of InferencePool from a Gateway.
151159
type PoolStatus struct {
152-
// GatewayRef indicates the gateway that observed state of InferencePool.
153-
GatewayRef ParentGatewayReference `json:"parentRef"`
154-
155160
// Conditions track the state of the InferencePool.
156161
//
157162
// Known condition types are:
@@ -165,6 +170,10 @@ type PoolStatus struct {
165170
// +kubebuilder:validation:MaxItems=8
166171
// +kubebuilder:default={{type: "Accepted", status: "Unknown", reason:"Pending", message:"Waiting for controller", lastTransitionTime: "1970-01-01T00:00:00Z"}}
167172
Conditions []metav1.Condition `json:"conditions,omitempty"`
173+
174+
// GatewayRef indicates the gateway that observed state of InferencePool.
175+
// +required
176+
GatewayRef ParentGatewayReference `json:"parentRef,omitzero"`
168177
}
169178

170179
// InferencePoolConditionType is a type of condition for the InferencePool
@@ -246,21 +255,22 @@ type ParentGatewayReference struct {
246255
//
247256
// +optional
248257
// +kubebuilder:default="gateway.networking.k8s.io"
249-
Group *Group `json:"group"`
258+
Group *Group `json:"group,omitempty"`
250259

251260
// Kind is kind of the referent. For example "Gateway".
252261
//
253262
// +optional
254263
// +kubebuilder:default=Gateway
255-
Kind *Kind `json:"kind"`
264+
Kind Kind `json:"kind,omitempty"`
256265

257266
// Name is the name of the referent.
258-
Name ObjectName `json:"name"`
267+
// +required
268+
Name ObjectName `json:"name,omitempty"`
259269

260270
// Namespace is the namespace of the referent. If not present,
261271
// the namespace of the referent is assumed to be the same as
262272
// the namespace of the referring object.
263273
//
264274
// +optional
265-
Namespace *Namespace `json:"namespace,omitempty"`
275+
Namespace Namespace `json:"namespace,omitempty"`
266276
}

api/v1/shared_types.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ package v1
3232
//
3333
// * "example.com/bar" - "/" is an invalid character
3434
//
35+
// +kubebuilder:validation:MinLength=0
3536
// +kubebuilder:validation:MaxLength=253
3637
// +kubebuilder:validation:Pattern=`^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`
3738
type Group string
@@ -135,7 +136,7 @@ type LabelSelector struct {
135136
// An object must match every label in this map to be selected.
136137
// The matching logic is an AND operation on all entries.
137138
//
138-
// +kubebuilder:validation:Required
139+
// +required
139140
// +kubebuilder:validation:MaxItems=64
140141
MatchLabels map[LabelKey]LabelValue `json:"matchLabels,omitempty" protobuf:"bytes,1,rep,name=matchLabels"`
141142
}

api/v1/zz_generated.deepcopy.go

Lines changed: 2 additions & 31 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apix/v1alpha2/inferencepool_conversion.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func (dst *InferencePool) ConvertFrom(src *v1.InferencePool) error {
5858
if src == nil {
5959
return errors.New("src cannot be nil")
6060
}
61-
extensionRef, err := convertExtensionRefFromV1(src.Spec.ExtensionRef)
61+
extensionRef, err := convertExtensionRefFromV1(&src.Spec.ExtensionRef)
6262
if err != nil {
6363
return err
6464
}
@@ -102,15 +102,19 @@ func convertStatusFromV1(src *v1.InferencePoolStatus) (*InferencePoolStatus, err
102102
return convert[InferencePoolStatus](u)
103103
}
104104

105-
func convertExtensionRefToV1(src *Extension) (*v1.Extension, error) {
105+
func convertExtensionRefToV1(src *Extension) (v1.Extension, error) {
106106
if src == nil {
107-
return nil, nil
107+
return v1.Extension{}, nil
108108
}
109109
u, err := toUnstructured(src)
110110
if err != nil {
111-
return nil, err
111+
return v1.Extension{}, err
112+
}
113+
out, err := convert[v1.Extension](u)
114+
if err != nil {
115+
return v1.Extension{}, err
112116
}
113-
return convert[v1.Extension](u)
117+
return *out, nil
114118
}
115119

116120
func convertExtensionRefFromV1(src *v1.Extension) (*Extension, error) {

apix/v1alpha2/inferencepool_conversion_test.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,12 @@ func TestInferencePoolConvertTo(t *testing.T) {
100100
},
101101
},
102102
TargetPortNumber: 8080,
103-
ExtensionRef: &v1.Extension{
103+
ExtensionRef: v1.Extension{
104104
Group: &v1Group,
105-
Kind: &v1Kind,
105+
Kind: v1Kind,
106106
Name: "my-epp-service",
107-
PortNumber: &v1PortNumber,
108-
FailureMode: &v1FailureMode,
107+
PortNumber: v1PortNumber,
108+
FailureMode: v1FailureMode,
109109
},
110110
},
111111
Status: v1.InferencePoolStatus{
@@ -235,12 +235,12 @@ func TestInferencePoolConvertFrom(t *testing.T) {
235235
},
236236
},
237237
TargetPortNumber: 8080,
238-
ExtensionRef: &v1.Extension{
238+
ExtensionRef: v1.Extension{
239239
Group: &v1Group,
240-
Kind: &v1Kind,
240+
Kind: v1Kind,
241241
Name: "my-epp-service",
242-
PortNumber: &v1PortNumber,
243-
FailureMode: &v1FailureMode,
242+
PortNumber: v1PortNumber,
243+
FailureMode: v1FailureMode,
244244
},
245245
},
246246
Status: v1.InferencePoolStatus{
@@ -348,6 +348,7 @@ func TestInferencePoolConvertFrom(t *testing.T) {
348348
"app": "my-model-server",
349349
},
350350
TargetPortNumber: 8080,
351+
ExtensionRef: &Extension{},
351352
},
352353
Status: InferencePoolStatus{
353354
Parents: []PoolStatus{

0 commit comments

Comments
 (0)