Skip to content

Commit 6e12d2b

Browse files
committed
add kube-api-linter and resolve API issues
Add kube-api-linter to `make lint`. kube-api-linter is based on golangci-lint v2, so it is upgraded to the latest version. kube-api-linter could be integrated with COSI CI in many ways. After experimentation, it is fastest to run it as a standalone install rather than build it each time `make lint` is run. Signed-off-by: Blaine Gardner <[email protected]>
1 parent dd3910f commit 6e12d2b

27 files changed

+385
-260
lines changed

.golangci.yaml

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,18 @@
1+
version: "2"
2+
13
run:
24
timeout: 5m
35
allow-parallel-runners: true
46

5-
issues:
6-
# don't skip warning about doc comments
7-
# don't exclude the default set of lint
8-
exclude-use-default: false
9-
# restore some of the defaults
10-
# (fill in the rest as needed)
11-
exclude-rules:
12-
- path: "apis/*"
13-
linters:
14-
- lll
15-
- path: "internal/*"
16-
linters:
17-
- dupl
18-
- lll
19-
- path: "_test.go"
20-
linters:
21-
- goconst
22-
237
linters:
24-
disable-all: true
8+
default: none
259
enable:
2610
- copyloopvar
2711
- dupl
2812
- errcheck
2913
- ginkgolinter
3014
- goconst
3115
- gocyclo
32-
- gofmt
33-
- goimports
34-
- gosimple
3516
- govet
3617
- ineffassign
3718
- lll
@@ -40,12 +21,32 @@ linters:
4021
- prealloc
4122
- revive
4223
- staticcheck
43-
- typecheck
4424
- unconvert
4525
- unparam
4626
- unused
4727

48-
linters-settings:
49-
revive:
28+
settings:
29+
revive:
30+
rules:
31+
- name: comment-spacings
32+
33+
exclusions:
34+
generated: lax
5035
rules:
51-
- name: comment-spacings
36+
- linters:
37+
- lll
38+
path: apis/*
39+
- linters:
40+
- dupl
41+
- lll
42+
path: internal/*
43+
- linters:
44+
- goconst
45+
path: _test.go
46+
47+
formatters:
48+
enable:
49+
- gofmt
50+
- goimports
51+
exclusions:
52+
generated: lax

Makefile

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,11 @@ export
5656
all: prebuild build ## Build all container images, plus their prerequisites (faster with 'make -j')
5757

5858
.PHONY: lint
59-
lint: golangci-lint.client golangci-lint.controller golangci-lint.sidecar spell-lint dockerfiles-lint ## Run all linters (suggest `make -k`)
59+
lint: golangci-lint.client golangci-lint.controller golangci-lint.sidecar kubeapi-lint spell-lint dockerfiles-lint ## Run all linters (suggest `make -k`)
6060
golangci-lint.%: golangci-lint
6161
cd $* && $(GOLANGCI_LINT) run $(GOLANGCI_LINT_RUN_OPTS) --config $(CURDIR)/.golangci.yaml --new
62+
kubeapi-lint: kube-api-linter
63+
cd client/apis && $(KUBEAPI_LINT) run --config $(CURDIR)/client/.kubeapilint.yaml
6264
spell-lint:
6365
git ls-files | grep -v -e CHANGELOG -e go.mod -e go.sum -e vendor | xargs $(SPELL_LINT) -i "Creater,creater,ect" -error -o stderr
6466
dockerfiles-lint:
@@ -192,6 +194,7 @@ CRD_REF_DOCS ?= $(TOOLBIN)/crd-ref-docs
192194
CTLPTL ?= $(TOOLBIN)/ctlptl
193195
GOLANGCI_LINT ?= $(TOOLBIN)/golangci-lint
194196
KIND ?= $(TOOLBIN)/kind
197+
KUBEAPI_LINT ?= $(TOOLBIN)/golangci-lint-kube-api-linter
195198
KUSTOMIZE ?= $(TOOLBIN)/kustomize
196199
MDBOOK ?= $(TOOLBIN)/mdbook
197200
SPELL_LINT ?= $(TOOLBIN)/spell-lint
@@ -201,8 +204,9 @@ CHAINSAW_VERSION ?= v0.2.12
201204
CONTROLLER_TOOLS_VERSION ?= v0.19.0
202205
CRD_REF_DOCS_VERSION ?= v0.2.0
203206
CTLPTL_VERSION ?= v0.8.39
204-
GOLANGCI_LINT_VERSION ?= v1.64.7
207+
GOLANGCI_LINT_VERSION ?= v2.7.2
205208
KIND_VERSION ?= v0.27.0
209+
KUBEAPI_LINT_VERSION ?= v0.0.0-20251208100930-d3015c953951
206210
KUSTOMIZE_VERSION ?= v5.6.0
207211
MDBOOK_VERSION ?= v0.4.47
208212
SPELL_LINT_VERSION ?= v0.6.0
@@ -238,6 +242,11 @@ kind: $(KIND)-$(KIND_VERSION)
238242
$(KIND)-$(KIND_VERSION): $(TOOLBIN)
239243
$(call go-install-tool,$(KIND),sigs.k8s.io/kind,$(KIND_VERSION))
240244

245+
.PHONY: kube-api-linter
246+
kube-api-linter: $(KUBEAPI_LINT)-$(KUBEAPI_LINT_VERSION)
247+
$(KUBEAPI_LINT)-$(KUBEAPI_LINT_VERSION): $(TOOLBIN)
248+
$(call go-install-tool,$(KUBEAPI_LINT),sigs.k8s.io/kube-api-linter/cmd/golangci-lint-kube-api-linter,$(KUBEAPI_LINT_VERSION))
249+
241250
.PHONY: kustomize
242251
kustomize: $(KUSTOMIZE)-$(KUSTOMIZE_VERSION)
243252
$(KUSTOMIZE)-$(KUSTOMIZE_VERSION): $(TOOLBIN)

client/.kubeapilint.yaml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# This is a golangci-lint configuration file specifically for kube-api-linter.
2+
3+
version: "2"
4+
5+
linters:
6+
default: none
7+
enable:
8+
- kubeapilinter
9+
10+
settings:
11+
custom:
12+
kubeapilinter:
13+
type: module
14+
description: Kube API Linter lints Kube like APIs based on API conventions and best practices.
15+
settings:
16+
linters:
17+
enable:
18+
- statussubresource
19+
- optionalfields # instead of nonpointerstructs
20+
- requiredfields # instead of nonpointerstructs
21+
disable:
22+
- nonpointerstructs # not intended for CRDs
23+
- statusoptional
24+
25+
lintersConfig:
26+
optionalfields:
27+
pointers:
28+
preference: WhenRequired

client/apis/objectstorage/v1alpha2/bucket_types.go

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -37,23 +37,23 @@ const (
3737
)
3838

3939
// BucketSpec defines the desired state of Bucket
40-
// +kubebuilder:validation:XValidation:message="parameters map is immutable",rule="has(oldSelf.parameters) == has(self.parameters)"
41-
// +kubebuilder:validation:XValidation:message="protocols list is immutable",rule="has(oldSelf.protocols) == has(self.protocols)"
42-
// +kubebuilder:validation:XValidation:message="existingBucketID is immutable",rule="has(oldSelf.existingBucketID) == has(self.existingBucketID)"
40+
// +kubebuilder:validation:XValidation:message="parameters map cannot be added or removed after creation",rule="has(oldSelf.parameters) == has(self.parameters)"
41+
// +kubebuilder:validation:XValidation:message="protocols list cannot be added or removed after creation",rule="has(oldSelf.protocols) == has(self.protocols)"
42+
// +kubebuilder:validation:XValidation:message="existingBucketID cannot be added or removed after creation",rule="has(oldSelf.existingBucketID) == has(self.existingBucketID)"
4343
type BucketSpec struct {
4444
// driverName is the name of the driver that fulfills requests for this Bucket.
4545
// +required
4646
// +kubebuilder:validation:MinLength=1
4747
// +kubebuilder:validation:XValidation:message="driverName is immutable",rule="self == oldSelf"
48-
DriverName string `json:"driverName"`
48+
DriverName string `json:"driverName,omitempty"`
4949

5050
// deletionPolicy determines whether a Bucket should be deleted when its bound BucketClaim is
5151
// deleted. This is mutable to allow Admins to change the policy after creation.
5252
// Possible values:
5353
// - Retain: keep both the Bucket object and the backend bucket
5454
// - Delete: delete both the Bucket object and the backend bucket
5555
// +required
56-
DeletionPolicy BucketDeletionPolicy `json:"deletionPolicy"`
56+
DeletionPolicy BucketDeletionPolicy `json:"deletionPolicy,omitempty"`
5757

5858
// parameters is an opaque map of driver-specific configuration items passed to the driver that
5959
// fulfills requests for this Bucket.
@@ -72,68 +72,70 @@ type BucketSpec struct {
7272
// For statically-provisioned buckets, set the namespace and name of the BucketClaim that is
7373
// allowed to bind to this Bucket.
7474
// +required
75-
BucketClaimRef BucketClaimReference `json:"bucketClaim"`
75+
BucketClaimRef BucketClaimReference `json:"bucketClaim,omitzero"`
7676

7777
// existingBucketID is the unique identifier for an existing backend bucket known to the driver.
7878
// Use driver documentation to determine how to set this value.
7979
// This field is used only for Bucket static provisioning.
8080
// This field will be empty when the Bucket is dynamically provisioned from a BucketClaim.
8181
// +optional
82+
// +kubebuilder:validation:MinLength=1
8283
// +kubebuilder:validation:XValidation:message="existingBucketID is immutable",rule="self == oldSelf"
8384
ExistingBucketID string `json:"existingBucketID,omitempty"`
8485
}
8586

8687
// BucketClaimReference is a reference to a BucketClaim object.
87-
// +kubebuilder:validation:XValidation:message="namespace is immutable once set",rule="!has(oldSelf.namespace) || has(self.namespace)"
88-
// +kubebuilder:validation:XValidation:message="uid is immutable once set",rule="!has(oldSelf.uid) || has(self.uid)"
88+
// +kubebuilder:validation:XValidation:message="namespace cannot be removed once set",rule="!has(oldSelf.namespace) || has(self.namespace)"
89+
// +kubebuilder:validation:XValidation:message="uid cannot be removed once set",rule="!has(oldSelf.uid) || has(self.uid)"
8990
type BucketClaimReference struct {
9091
// name is the name of the BucketClaim being referenced.
9192
// +required
9293
// +kubebuilder:validation:MinLength=1
9394
// +kubebuilder:validation:MaxLength=253
9495
// +kubebuilder:validation:XValidation:message="name is immutable",rule="self == oldSelf"
95-
Name string `json:"name"`
96+
Name string `json:"name,omitempty"`
9697

9798
// namespace is the namespace of the BucketClaim being referenced.
98-
// If empty, the Kubernetes 'default' namespace is assumed.
99-
// namespace is immutable except to update '' to 'default'.
100-
// +optional
101-
// +kubebuilder:validation:MinLength=0
99+
// +required
100+
// +kubebuilder:validation:MinLength=1
102101
// +kubebuilder:validation:MaxLength=253
103-
// +kubebuilder:validation:XValidation:message="namespace is immutable",rule="(oldSelf == '' && self == 'default') || self == oldSelf"
104-
Namespace string `json:"namespace"`
102+
// +kubebuilder:validation:XValidation:message="namespace is immutable",rule="self == oldSelf"
103+
Namespace string `json:"namespace,omitempty"`
105104

106105
// uid is the UID of the BucketClaim being referenced.
107106
// +optional
108107
// +kubebuilder:validation:XValidation:message="uid is immutable once set",rule="oldSelf == '' || self == oldSelf"
109-
UID types.UID `json:"uid"`
108+
UID types.UID `json:"uid,omitempty"`
110109
}
111110

112111
// BucketStatus defines the observed state of Bucket.
113-
// +kubebuilder:validation:XValidation:message="bucketID is immutable once set",rule="!has(oldSelf.bucketID) || has(self.bucketID)"
114-
// +kubebuilder:validation:XValidation:message="protocols is immutable once set",rule="!has(oldSelf.protocols) || has(self.protocols)"
112+
// +kubebuilder:validation:XValidation:message="bucketID cannot be removed once set",rule="!has(oldSelf.bucketID) || has(self.bucketID)"
113+
// +kubebuilder:validation:XValidation:message="protocols cannot be removed once set",rule="!has(oldSelf.protocols) || has(self.protocols)"
115114
type BucketStatus struct {
116115
// readyToUse indicates that the bucket is ready for consumption by workloads.
117-
ReadyToUse bool `json:"readyToUse"`
116+
// +required
117+
ReadyToUse *bool `json:"readyToUse,omitempty"`
118118

119119
// bucketID is the unique identifier for the backend bucket known to the driver.
120120
// +optional
121-
// +kubebuilder:validation:XValidation:message="boundBucketName is immutable once set",rule="oldSelf == '' || self == oldSelf"
122-
BucketID string `json:"bucketID"`
121+
// +kubebuilder:validation:MinLength=1
122+
// +kubebuilder:validation:XValidation:message="boundBucketName is immutable once set",rule="self == oldSelf"
123+
BucketID string `json:"bucketID,omitempty"`
123124

124125
// protocols is the set of protocols the Bucket reports to support. BucketAccesses can request
125126
// access to this BucketClaim using any of the protocols reported here.
126127
// +optional
127128
// +listType=set
128-
Protocols []ObjectProtocol `json:"protocols"`
129+
Protocols []ObjectProtocol `json:"protocols,omitempty"`
129130

130-
// BucketInfo reported by the driver, rendered in the COSI_<PROTOCOL>_<KEY> format used for the
131-
// BucketAccess Secret. e.g., COSI_S3_ENDPOINT, COSI_AZURE_STORAGE_ACCOUNT.
131+
// bucketInfo contains info about the bucket reported by the driver, rendered in the same
132+
// COSI_<PROTOCOL>_<KEY> format used for the BucketAccess Secret.
133+
// e.g., COSI_S3_ENDPOINT, COSI_AZURE_STORAGE_ACCOUNT.
132134
// This should not contain any sensitive information.
133135
// +optional
134136
BucketInfo map[string]string `json:"bucketInfo,omitempty"`
135137

136-
// Error holds the most recent error message, with a timestamp.
138+
// error holds the most recent error message, with a timestamp.
137139
// This is cleared when provisioning is successful.
138140
// +optional
139141
Error *TimestampedError `json:"error,omitempty"`
@@ -154,11 +156,11 @@ type Bucket struct {
154156

155157
// spec defines the desired state of Bucket
156158
// +required
157-
Spec BucketSpec `json:"spec"`
159+
Spec BucketSpec `json:"spec,omitzero"`
158160

159161
// status defines the observed state of Bucket
160162
// +optional
161-
Status BucketStatus `json:"status,omitempty,omitzero"`
163+
Status BucketStatus `json:"status,omitzero"`
162164
}
163165

164166
// +kubebuilder:object:root=true

0 commit comments

Comments
 (0)