Skip to content

Commit a4d0828

Browse files
committed
Improve API docs and validation
From API review, make sure all APIs have documentation that allows users to better interact with the API using `kubectl explain`. Ensure all possible input and output values are noted with text explaining what values mean. Also ensure all API fields have validation that prevents abuse. Signed-off-by: Blaine Gardner <blaine.gardner@ibm.com>
1 parent e8ad800 commit a4d0828

25 files changed

+585
-93
lines changed

client/.kubeapilint.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ linters:
1818
- statussubresource
1919
- optionalfields # instead of nonpointerstructs
2020
- requiredfields # instead of nonpointerstructs
21+
- maxlength
2122
disable:
2223
- nonpointerstructs # not intended for CRDs
2324
- statusoptional

client/apis/objectstorage/v1alpha2/bucket_types.go

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,13 @@ const (
4242
// +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.
45+
// See driver documentation to determine the correct value to set.
46+
// Must be 63 characters or less, beginning and ending with an alphanumeric character
47+
// ([a-z0-9A-Z]) with dashes (-), dots (.), and alphanumerics between.
4548
// +required
4649
// +kubebuilder:validation:MinLength=1
50+
// +kubebuilder:validation:MaxLength=63
51+
// +kubebuilder:validation:Pattern=`^[a-zA-Z0-9]([a-zA-Z0-9\-\.]{0,61}[a-zA-Z0-9])?$`
4752
// +kubebuilder:validation:XValidation:message="driverName is immutable",rule="self == oldSelf"
4853
DriverName string `json:"driverName,omitempty"`
4954

@@ -57,29 +62,41 @@ type BucketSpec struct {
5762

5863
// parameters is an opaque map of driver-specific configuration items passed to the driver that
5964
// fulfills requests for this Bucket.
65+
// See driver documentation to determine supported parameters and their effects.
66+
// A maximum of 512 parameters are allowed.
6067
// +optional
68+
// +kubebuilder:validation:MinProperties=1
69+
// +kubebuilder:validation:MaxProperties=512
6170
// +kubebuilder:validation:XValidation:message="parameters map is immutable",rule="self == oldSelf"
6271
Parameters map[string]string `json:"parameters,omitempty"`
6372

6473
// protocols lists object store protocols that the provisioned Bucket must support.
6574
// If specified, COSI will verify that each item is advertised as supported by the driver.
75+
// See driver documentation to determine supported protocols.
76+
// Possible values: 'S3', 'Azure', 'GCS'.
6677
// +optional
6778
// +listType=set
79+
// +kubebuilder:validation:MinItems=1
80+
// +kubebuilder:validation:MaxItems=3
6881
// +kubebuilder:validation:XValidation:message="protocols list is immutable",rule="self == oldSelf"
6982
Protocols []ObjectProtocol `json:"protocols,omitempty"`
7083

71-
// bucketClaim references the BucketClaim that resulted in the creation of this Bucket.
84+
// bucketClaimRef references the BucketClaim that resulted in the creation of this Bucket.
7285
// For statically-provisioned buckets, set the namespace and name of the BucketClaim that is
73-
// allowed to bind to this Bucket.
86+
// allowed to bind to this Bucket; UID may be left unset if desired and will be updated by COSI.
7487
// +required
75-
BucketClaimRef BucketClaimReference `json:"bucketClaim,omitzero"`
88+
BucketClaimRef BucketClaimReference `json:"bucketClaimRef,omitzero"`
7689

7790
// existingBucketID is the unique identifier for an existing backend bucket known to the driver.
78-
// Use driver documentation to determine how to set this value.
79-
// This field is used only for Bucket static provisioning.
91+
// Use driver documentation to determine the correct value to set.
92+
// This field is used only for static Bucket provisioning.
8093
// This field will be empty when the Bucket is dynamically provisioned from a BucketClaim.
94+
// Must be at most 2048 characters and consist only of alphanumeric characters ([a-z0-9A-Z]),
95+
// dashes (-), dots (.), and underscores (_).
8196
// +optional
8297
// +kubebuilder:validation:MinLength=1
98+
// +kubebuilder:validation:MaxLength=2048
99+
// +kubebuilder:validation:Pattern=`^[a-zA-Z0-9._-]+$`
83100
// +kubebuilder:validation:XValidation:message="existingBucketID is immutable",rule="self == oldSelf"
84101
ExistingBucketID string `json:"existingBucketID,omitempty"`
85102
}
@@ -89,21 +106,34 @@ type BucketSpec struct {
89106
// +kubebuilder:validation:XValidation:message="uid cannot be removed once set",rule="!has(oldSelf.uid) || has(self.uid)"
90107
type BucketClaimReference struct {
91108
// name is the name of the BucketClaim being referenced.
109+
// Must be a valid Kubernetes resource name: at most 253 characters, consisting only of
110+
// lower-case alphanumeric characters, hyphens, and periods, starting and ending with an
111+
// alphanumeric character.
92112
// +required
93113
// +kubebuilder:validation:MinLength=1
94114
// +kubebuilder:validation:MaxLength=253
115+
// +kubebuilder:validation:XValidation:message="name must be a valid resource name",rule="!format.dns1123Subdomain().validate(self).hasValue()"
95116
// +kubebuilder:validation:XValidation:message="name is immutable",rule="self == oldSelf"
96117
Name string `json:"name,omitempty"`
97118

98119
// namespace is the namespace of the BucketClaim being referenced.
120+
// Must be a valid Kubernetes Namespace name: at most 63 characters, consisting only of
121+
// lower-case alphanumeric characters and hyphens, starting and ending with alphanumerics.
99122
// +required
100123
// +kubebuilder:validation:MinLength=1
101-
// +kubebuilder:validation:MaxLength=253
124+
// +kubebuilder:validation:MaxLength=63
125+
// +kubebuilder:validation:XValidation:message="namespace must be a valid namespace name",rule="!format.dns1123Label().validate(self).hasValue()"
102126
// +kubebuilder:validation:XValidation:message="namespace is immutable",rule="self == oldSelf"
103127
Namespace string `json:"namespace,omitempty"`
104128

105129
// uid is the UID of the BucketClaim being referenced.
130+
// Must be a valid Kubernetes UID: RFC 4122 form with lowercase hexadecimal characters
131+
// (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
106132
// +optional
133+
// +kubebuilder:validation:MinLength=36
134+
// +kubebuilder:validation:MaxLength=36
135+
// +kubebuilder:validation:Type=string
136+
// +kubebuilder:validation:Pattern=`^[0-9a-f]{8}-([0-9a-f]{4}\-){3}[0-9a-f]{12}$`
107137
// +kubebuilder:validation:XValidation:message="uid is immutable once set",rule="oldSelf == '' || self == oldSelf"
108138
UID types.UID `json:"uid,omitempty"`
109139
}
@@ -117,22 +147,31 @@ type BucketStatus struct {
117147
ReadyToUse *bool `json:"readyToUse,omitempty"`
118148

119149
// bucketID is the unique identifier for the backend bucket known to the driver.
150+
// Must be at most 2048 characters and consist only of alphanumeric characters ([a-z0-9A-Z]),
151+
// dashes (-), dots (.), and underscores (_).
120152
// +optional
121153
// +kubebuilder:validation:MinLength=1
154+
// +kubebuilder:validation:MaxLength=2048
155+
// +kubebuilder:validation:Pattern=`^[a-zA-Z0-9._-]+$`
122156
// +kubebuilder:validation:XValidation:message="boundBucketName is immutable once set",rule="self == oldSelf"
123157
BucketID string `json:"bucketID,omitempty"`
124158

125159
// protocols is the set of protocols the Bucket reports to support. BucketAccesses can request
126-
// access to this BucketClaim using any of the protocols reported here.
160+
// access to this Bucket using any of the protocols reported here.
161+
// Possible values: 'S3', 'Azure', 'GCS'.
127162
// +optional
128163
// +listType=set
164+
// +kubebuilder:validation:MinItems=1
165+
// +kubebuilder:validation:MaxItems=3
129166
Protocols []ObjectProtocol `json:"protocols,omitempty"`
130167

131168
// bucketInfo contains info about the bucket reported by the driver, rendered in the same
132169
// COSI_<PROTOCOL>_<KEY> format used for the BucketAccess Secret.
133170
// e.g., COSI_S3_ENDPOINT, COSI_AZURE_STORAGE_ACCOUNT.
134171
// This should not contain any sensitive information.
135172
// +optional
173+
// +kubebuilder:validation:MinProperties=1
174+
// +kubebuilder:validation:MaxProperties=128
136175
BucketInfo map[string]string `json:"bucketInfo,omitempty"`
137176

138177
// error holds the most recent error message, with a timestamp.

client/apis/objectstorage/v1alpha2/bucketaccess_types.go

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,13 @@ type BucketAccessSpec struct {
5858
// bucketClaims is a list of BucketClaims the provisioned access must have permissions for,
5959
// along with per-BucketClaim access parameters and system output definitions.
6060
// At least one BucketClaim must be referenced.
61+
// A maximum of 128 BucketClaims may be referenced.
6162
// Multiple references to the same BucketClaim are not permitted.
6263
// +required
6364
// +listType=map
6465
// +listMapKey=bucketClaimName
6566
// +kubebuilder:validation:MinItems=1
67+
// +kubebuilder:validation:MaxItems=128
6668
// +kubebuilder:validation:XValidation:message="bucketClaims list is immutable",rule="self == oldSelf"
6769
BucketClaims []BucketClaimAccess `json:"bucketClaims,omitempty"`
6870

@@ -74,16 +76,18 @@ type BucketAccessSpec struct {
7476
BucketAccessClassName string `json:"bucketAccessClassName,omitempty"`
7577

7678
// protocol is the object storage protocol that the provisioned access must use.
79+
// Access can only be granted for BucketClaims that support the requested protocol.
80+
// Each BucketClaim status reports which protocols are supported for the BucketClaim's bucket.
81+
// Possible values: 'S3', 'Azure', 'GCS'.
7782
// +required
7883
// +kubebuilder:validation:XValidation:message="protocol is immutable",rule="self == oldSelf"
7984
Protocol ObjectProtocol `json:"protocol,omitempty"`
8085

8186
// serviceAccountName is the name of the Kubernetes ServiceAccount that user application Pods
8287
// intend to use for access to referenced BucketClaims.
83-
// This has different behavior based on the BucketAccessClass's defined AuthenticationType:
84-
// - Key: This field is ignored.
85-
// - ServiceAccount: This field is required. The driver should configure the system so that Pods
86-
// using the ServiceAccount authenticate to the object storage backend automatically.
88+
// Required when the BucketAccessClass is configured to use ServiceAccount authentication type.
89+
// Ignored for all other authentication types.
90+
// It is recommended to specify this for all BucketAccesses to improve portability.
8791
// +optional
8892
// +kubebuilder:validation:MinLength=1
8993
// +kubebuilder:validation:MaxLength=253
@@ -104,8 +108,12 @@ type BucketAccessStatus struct {
104108

105109
// accountID is the unique identifier for the backend access known to the driver.
106110
// This field is populated by the COSI Sidecar once access has been successfully granted.
111+
// Must be at most 2048 characters and consist only of alphanumeric characters ([a-z0-9A-Z]),
112+
// dashes (-), dots (.), and underscores (_).
107113
// +optional
108114
// +kubebuilder:validation:MinLength=1
115+
// +kubebuilder:validation:MaxLength=2048
116+
// +kubebuilder:validation:Pattern=`^[a-zA-Z0-9._-]+$`
109117
// +kubebuilder:validation:XValidation:message="accountId is immutable once set",rule="self == oldSelf"
110118
AccountID string `json:"accountID,omitempty"`
111119

@@ -116,25 +124,35 @@ type BucketAccessStatus struct {
116124
// +listType=map
117125
// +listMapKey=bucketName
118126
// +kubebuilder:validation:MinItems=1
127+
// +kubebuilder:validation:MaxItems=128
119128
// +kubebuilder:validation:XValidation:message="accessedBuckets is immutable once set",rule="self == oldSelf"
120129
AccessedBuckets []AccessedBucket `json:"accessedBuckets,omitempty"`
121130

122131
// driverName holds a copy of the BucketAccessClass driver name from the time of BucketAccess
123132
// provisioning. This field is populated by the COSI Controller.
133+
// Must be 63 characters or less, beginning and ending with an alphanumeric character
134+
// ([a-z0-9A-Z]) with dashes (-), dots (.), and alphanumerics between.
124135
// +optional
125136
// +kubebuilder:validation:MinLength=1
137+
// +kubebuilder:validation:MaxLength=63
138+
// +kubebuilder:validation:Pattern=`^[a-zA-Z0-9]([a-zA-Z0-9\-\.]{0,61}[a-zA-Z0-9])?$`
126139
// +kubebuilder:validation:XValidation:message="driverName is immutable once set",rule="self == oldSelf"
127140
DriverName string `json:"driverName,omitempty"`
128141

129142
// authenticationType holds a copy of the BucketAccessClass authentication type from the time of
130143
// BucketAccess provisioning. This field is populated by the COSI Controller.
144+
// Possible values:
145+
// - Key: clients may use a protocol-appropriate access key to authenticate to the backend object store.
146+
// - ServiceAccount: Pods using the ServiceAccount given in spec.serviceAccountName may authenticate to the backend object store automatically.
131147
// +optional
132148
// +kubebuilder:validation:XValidation:message="authenticationType is immutable once set",rule="self == oldSelf"
133149
AuthenticationType BucketAccessAuthenticationType `json:"authenticationType,omitempty"`
134150

135151
// parameters holds a copy of the BucketAccessClass parameters from the time of BucketAccess
136152
// provisioning. This field is populated by the COSI Controller.
137153
// +optional
154+
// +kubebuilder:validation:MinProperties=1
155+
// +kubebuilder:validation:MaxProperties=512
138156
// +kubebuilder:validation:XValidation:message="accessedBuckets is immutable once set",rule="self == oldSelf"
139157
Parameters map[string]string `json:"parameters,omitempty"`
140158

@@ -150,13 +168,22 @@ type BucketAccessStatus struct {
150168
type BucketClaimAccess struct {
151169
// bucketClaimName is the name of a BucketClaim the access should have permissions for.
152170
// The BucketClaim must be in the same Namespace as the BucketAccess.
171+
// Must be a valid Kubernetes resource name: at most 253 characters, consisting only of
172+
// lower-case alphanumeric characters, hyphens, and periods, starting and ending with an
173+
// alphanumeric character.
153174
// +required
154175
// +kubebuilder:validation:MinLength=1
155176
// +kubebuilder:validation:MaxLength=253
177+
// +kubebuilder:validation:XValidation:message="name must be a valid resource name",rule="!format.dns1123Subdomain().validate(self).hasValue()"
156178
BucketClaimName string `json:"bucketClaimName,omitempty"`
157179

158180
// accessMode is the Read/Write access mode that the access should have for the bucket.
159-
// Possible values: ReadWrite, ReadOnly, WriteOnly.
181+
// The provisioned access will have the corresponding permissions to read and/or write objects
182+
// the BucketClaim's bucket.
183+
// The provisioned access can also assume to have corresponding permissions to read and/or write
184+
// object metadata and object metadata (e.g., tags) except when metadata changes would change
185+
// object store behaviors or permissions (e.g., changes to object caching behaviors).
186+
// Possible values: 'ReadWrite', 'ReadOnly', 'WriteOnly'.
160187
// +required
161188
AccessMode BucketAccessMode `json:"accessMode,omitempty"`
162189

@@ -166,24 +193,36 @@ type BucketClaimAccess struct {
166193
// BucketAccess is deleted and deprovisioned.
167194
// The Secret name must be unique across all bucketClaimRefs for all BucketAccesses in the same
168195
// Namespace.
196+
// Must be a valid Kubernetes resource name: at most 253 characters, consisting only of
197+
// lower-case alphanumeric characters, hyphens, and periods, starting and ending with an
198+
// alphanumeric character.
169199
// +required
170200
// +kubebuilder:validation:MinLength=1
171201
// +kubebuilder:validation:MaxLength=253
202+
// +kubebuilder:validation:XValidation:message="name must be a valid resource name",rule="!format.dns1123Subdomain().validate(self).hasValue()"
172203
AccessSecretName string `json:"accessSecretName,omitempty"`
173204
}
174205

175206
// AccessedBucket identifies a Bucket and correlates it to a BucketClaimAccess from the spec.
176207
type AccessedBucket struct {
177208
// bucketName is the name of a Bucket the access should have permissions for.
209+
// Must be a valid Kubernetes resource name: at most 253 characters, consisting only of
210+
// lower-case alphanumeric characters, hyphens, and periods, starting and ending with an
211+
// alphanumeric character.
178212
// +required
179213
// +kubebuilder:validation:MinLength=1
180214
// +kubebuilder:validation:MaxLength=253
215+
// +kubebuilder:validation:XValidation:message="name must be a valid resource name",rule="!format.dns1123Subdomain().validate(self).hasValue()"
181216
BucketName string `json:"bucketName,omitempty"`
182217

183218
// bucketClaimName must match a BucketClaimAccess's BucketClaimName from the spec.
219+
// Must be a valid Kubernetes resource name: at most 253 characters, consisting only of
220+
// lower-case alphanumeric characters, hyphens, and periods, starting and ending with an
221+
// alphanumeric character.
184222
// +required
185223
// +kubebuilder:validation:MinLength=1
186224
// +kubebuilder:validation:MaxLength=253
225+
// +kubebuilder:validation:XValidation:message="name must be a valid resource name",rule="!format.dns1123Subdomain().validate(self).hasValue()"
187226
BucketClaimName string `json:"bucketClaimName,omitempty"`
188227
}
189228

client/apis/objectstorage/v1alpha2/bucketaccessclass_types.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,17 @@ import (
2323
// BucketAccessClassSpec defines the desired state of BucketAccessClass
2424
type BucketAccessClassSpec struct {
2525
// driverName is the name of the driver that fulfills requests for this BucketAccessClass.
26+
// See driver documentation to determine the correct value to set.
27+
// Must be 63 characters or less, beginning and ending with an alphanumeric character
28+
// ([a-z0-9A-Z]) with dashes (-), dots (.), and alphanumerics between.
2629
// +required
2730
// +kubebuilder:validation:MinLength=1
31+
// +kubebuilder:validation:MaxLength=63
32+
// +kubebuilder:validation:Pattern=`^[a-zA-Z0-9]([a-zA-Z0-9\-\.]{0,61}[a-zA-Z0-9])?$`
2833
DriverName string `json:"driverName,omitempty"`
2934

3035
// authenticationType specifies which authentication mechanism is used bucket access.
36+
// See driver documentation to determine which values are supported.
3137
// Possible values:
3238
// - Key: The driver should generate a protocol-appropriate access key that clients can use to
3339
// authenticate to the backend object store.
@@ -38,7 +44,11 @@ type BucketAccessClassSpec struct {
3844

3945
// parameters is an opaque map of driver-specific configuration items passed to the driver that
4046
// fulfills requests for this BucketAccessClass.
47+
// See driver documentation to determine supported parameters and their effects.
48+
// A maximum of 512 parameters are allowed.
4149
// +optional
50+
// +kubebuilder:validation:MinProperties=1
51+
// +kubebuilder:validation:MaxProperties=512
4252
Parameters map[string]string `json:"parameters,omitempty"`
4353

4454
// featureOptions can be used to adjust various COSI access provisioning behaviors.
@@ -53,8 +63,13 @@ type BucketAccessFeatureOptions struct {
5363
// disallowedBucketAccessModes is a list of disallowed Read/Write access modes. A BucketAccess
5464
// using this class will not be allowed to request access to a BucketClaim with any access mode
5565
// listed here.
66+
// This is particularly useful for administrators to restrict access to a statically-provisioned
67+
// bucket that is managed outside the BucketAccess Namespace or Kubernetes cluster.
68+
// Possible values: 'ReadWrite', 'ReadOnly', 'WriteOnly'.
5669
// +optional
5770
// +listType=set
71+
// +kubebuilder:validation:MinItems=1
72+
// +kubebuilder:validation:MaxItems=3
5873
DisallowedBucketAccessModes []BucketAccessMode `json:"disallowedBucketAccessModes,omitempty"`
5974

6075
// disallowMultiBucketAccess disables the ability for a BucketAccess to reference multiple

0 commit comments

Comments
 (0)