-
Notifications
You must be signed in to change notification settings - Fork 18
API Review PR #199
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
API Review PR #199
Conversation
|
Skipping CI for Draft Pull Request. |
✅ Deploy Preview for container-object-storage-interface ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: BlaineEXE The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
JoelSpeed
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I stopped at a point here as I think a lot of what I've said I'm now repeating for fields further on the review. I'd recommend implementing Kube-api-linter here to help with reminders on best practices (using omitempty everywhere, setting min/max lengths consistently)
Please review my feedback and apply anywhere it seems repeated across the API surface in this PR
| // +kubebuilder:validation:XValidation:message="protocols list is immutable",rule="has(oldSelf.protocols) == has(self.protocols)" | ||
| // +kubebuilder:validation:XValidation:message="existingBucketID is immutable",rule="has(oldSelf.existingBucketID) == has(self.existingBucketID)" | ||
| type BucketSpec struct { | ||
| // driverName is the name of the driver that fulfills requests for this Bucket. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you considered what valid data for this field looks like? What is the possible format of a driver name? Must it conform to any pattern (e.g. must it be a valid K8s resource name?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably be in line with other Kubernetes names, following RFC1123.
| type BucketSpec struct { | ||
| // driverName is the name of the driver that fulfills requests for this Bucket. | ||
| // +required | ||
| // +kubebuilder:validation:MinLength=1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about a maximum length?
| // Possible values: | ||
| // - Retain: keep both the Bucket object and the backend bucket | ||
| // - Delete: delete both the Bucket object and the backend bucket |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd recommend trying kubectl explain on this field. I don't think this will render as it is written here.
I generally recommend full sentences over bullets for this reason.
| // Possible values: | |
| // - Retain: keep both the Bucket object and the backend bucket | |
| // - Delete: delete both the Bucket object and the backend bucket | |
| // Valid values are Retain and Delete. | |
| // When set to Retain, both the Bucket object and the backend bucket will be kept upon deletion. | |
| // When set to Delete, both the Bucket object and the backend bucket will be removed upon deletion. |
| // parameters is an opaque map of driver-specific configuration items passed to the driver that | ||
| // fulfills requests for this Bucket. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is a driver here? How would I know what valid options are? Is this CLI args, or a config file?
What happens if a bucket needs more flexibility for configuration than string to string allows?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those are open options - how they are used it's up to the driver's implementation details, and should be documented in the specific driver's documentation. If one needs to have more flexibility here, they can use JSON/YAML in strings or reference config maps or secrets through that field.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the driver will effectively come up with a schema here and will be given a raw blob of data? Or how are you passing the data to the driver? Do you have any more context on this?
I'm wondering if a map here is the right thing to do, vs just being a raw blob of unstructured data
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This reminds me of the early days of cluster API, we found raw data to be awkward and eventually switch to references to concrete CRs. Have you seen this pattern before? Or considered it here?
It would mean that each driver has its own config type that can be properly structured, can be evolved over time and provide proper validations
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One of the goals of COSI is to do our best to balance familiarity with StorageClass/PV/PVC concepts against new designs that allow better usability. This is a case where COSI has borrowed the same opaque map concept from StorageClass.
My gut feel here is that this is still sufficient for block and file storage and that it will probably be slightly more beneficial to keep similar semantics. However, I will make a note to ask in the sig-storage group if there have been discussions to change this and solicit feedback.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This reminds me of the early days of cluster API, we found raw data to be awkward and eventually switch to references to concrete CRs. Have you seen this pattern before? Or considered it here?
Yes, and I don't like this design from user's perspective. Balancing few different vendors and CAPI itself is painful, especially if you want to keep up to date. I'd like to keep it simple, using k/v pairs as here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I spoke to sig-storage folks about this topic today, and they reported that the opaque parameter map has worked well for some time for StorageClasses, PVCs, and CSI. Unless additional info comes up here, the takeaway is that COSI and sig-storage prefer to keep this as-is to rely on user/driver/admin familiarity from CSI.
I consider this resolved, but I'll opt to leave this thread open because I think it will be a good reference in the future. Thanks again, Joel.
| // protocols lists object store protocols that the provisioned Bucket must support. | ||
| // If specified, COSI will verify that each item is advertised as supported by the driver. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are the valid protocol types? Should include the valid options here to that users can see from the docs what the valid options are
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be set through // +kubebuilder:validation:Enum, right? Do we need this separately in the comment though?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be set through // +kubebuilder:validation:Enum, right?
Yes, though I thought this was already done?
Most end user documentation is generated only from the godoc. It doesn't include the enum or other validations from the schema. Which means that when a user reads the docs for the field (e.g. kubectl explain), they would have no idea what the valid options are unless we tell them in the godoc
| // +kubebuilder:validation:MinLength=1 | ||
| // +kubebuilder:validation:MaxLength=253 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DNS 1123 subdomain feedback? Bucket here is a kube object or an external object?
| // +kubebuilder:validation:MinLength=1 | ||
| // +kubebuilder:validation:MaxLength=253 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DNS 1123 subdomain feedback here
| // Non-relevant vars will not be present, even when marked "Required". | ||
| // Vars are used as data keys in BucketAccess Secrets. | ||
| // Vars must be all-caps and must begin with `COSI_`. | ||
| type CosiEnvVar string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why represent all of these as env vars in your API vs something more structured?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oof. This is a question. 😅
In v1a1, we had this as a structured type that was rendered into a JSON blob in the Secret that users use to consume the info. In the best case, an application would read the file directly. In usual cases, an init container with jq would process the file into something that the main container would use.
However, we got feedback from a few users that there are scenarios where this just wasn't possible, and users instead wanted individual Secret fields for each item.
These are fields that must remain secret, so we can't encode them into a status. We have to use a secret.
So this is our best attempt to have some reliable structure for end users within Secret data fields.
If you have other suggestions, we will be happy to consider them. I can't say I love this approach, but it's the best we've been able to come up with given our constraints.
| // BucketAccess Secret. e.g., COSI_S3_ENDPOINT, COSI_AZURE_STORAGE_ACCOUNT. | ||
| // This should not contain any sensitive information. | ||
| // +optional | ||
| BucketInfo map[string]string `json:"bucketInfo,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be better as a list of named objects, easier to apply validation and allow SSA style writes
bucketInfo:
- property: Blah
value: something
|
|
||
| // featureOptions can be used to adjust various COSI access provisioning behaviors. | ||
| // +optional | ||
| FeatureOptions BucketAccessFeatureOptions `json:"featureOptions,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feature options feels a bit odd here, why not make this more about bucket access. Also, try to avoid the bool here
bucketAccess: <- you can probably come up with something better?
disallowedModes: ["S3", ... ]
concurrency: Singular | Multi
|
Thanks, Joel, for the very thorough review so far and the help understanding the suggestions. I am beginning my work to resolve the issues by finishing the open issue to run kube-api-linter and address those issues. After that, I'll keep addressing the minor points bit by bit, and I will begin discuss the bigger questions like |
This PR is not intended to be merged. I have merely copied the current WIP API that is proposed in the v1alpha2 KEP PR to solicit more technical feedback.
This PR will not be merged directly, but feedback will be taken and made in other PRs.