-
Notifications
You must be signed in to change notification settings - Fork 129
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
Add support for Konnect documents #336
Conversation
Supersedes #328. Attempting to PR the individual type/service, dump, state, and file writing components was confusing, since the components don't make much sense when added in isolation. As of now, this draft implements a working PoC for the dump command only. |
Add basic state management and file output for Konnect Documents. Doesn't yet handle writing content to separate files.
16d182d
to
a9bee1f
Compare
Write Document resources' content strings to files within directories generated from the Service Package Name and Service Version Version. This does not yet handle escaping "/" characters, which are permitted in Names and Versions.
a9bee1f
to
e7d7ee2
Compare
Copy/paste of Michal's comment on the previous PR: What do you think about an alternative/polymorphic API structure like below? Assuming the following:
it stood out to me that If we make the following change:
we'll free
|
I like the proposed interface for parent URLs in the type service, but don't see how we can elegantly achieve something similar in state/document.go. The indices in the schema there reference specific other memdb tables, and I don't think there's any way we can get away from that. We can perhaps get away from everything but that by exposing the state index constants outside the package and using those in
with:
The existing pattern is for state to define dedicated functions for each index, but I don't think there's much reason to use those versus a generic function that accepts an index argument: the file package code is already aware of what index it needs to use (hence how it knows which function is appropriate). Edit: having played around with the state part a bit now, we also need some new way to handle index population. |
Replace the dedicated Service Version and Service Package functions for Documents with a generic ParentInfoer interface and associated functions. A ParentInfoer can indicate an API URL prefix that supports requests for associated child objects (e.g. the prefix "/api/service_packages" supports all Document interactions with the "/documents" suffix, as does "/api/service_versions") and can return the parent's ID and type, (to provide index keys in the state DB). Document state schema simplified to use a single foreign/parent object index. Parents are responsible for generating keys that do not conflict with other types of parents' keys.
2971f21 implements the parent interface suggestion. state/document.go is probably best viewed as-is; the diff from the previous version doesn't make much sense. I don't think using separate indices for Service Version/Package relationships in state is possible without essentially violating the goals of using the generic interface. Populating separate indices would probably extending the MethodIndexer to accept arguments require some convoluted method that returned nothing when invoked for a document whose parent didn't match the index type. Requiring that parents generate their own key and relying on key method authors not to introduce conflicts isn't ironclad, but seems a reasonable ask given that the keys are simple. Not sure what happened to deepcopy generation or why that's failing only on the push. |
Add tests for document state management. Add additional document state functions for parity with other state types. Add additional error handling to existing document state functions.
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.
Looking at DeepCopyParentInfoer
, I need to better understand why DeepCopy
needs to made a deep copy the parent as well. What do we need the deep copy for, and do linked entities (here: the parent) need to be deep-copied as well?
file/writer.go
Outdated
if err := os.MkdirAll(prefix+*sp.Name, 0700); err != nil { | ||
return errors.Wrap(err, "creating document directory") | ||
} |
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.
Shouldn't this happen in the outer loop? You want to mkdir
just once per service package, right? Probably with a if len(sp.Documents) > 0
.
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.
Something of a leftover from an earlier understanding of the document objects (handled incorrectly, to boot).
Originally, our reading of the Document Path
value was that it was actually a filesystem path, and that we'd need to create a nested structure under the SP/SV directories to handle the complete path. The original code didn't actually do this: handling those paths properly would require a MkdirAll()
per document.
In practice, Konnect doesn't use Path
like a filesystem path, and per confirmation from Henri P.:
Paths are only used as display names
The rework in 575c8fa works off that understanding and creates the SP/SV directories only once, and only if they have an attached document.
- Only create a directory (once) if an SP or SV has an associated document. - Use OS-agnostic path functions. - Add a utility to escape path separators for entity fields we use as directory or file names.
Konnect commands work with additional files when handling documents. This does not work nicely with stdin/stdout mode, as it'd send some output (the resource manifest/konnect.yaml) to stdout and some (document contents) to the filesystem. The simplest option to handle this is to disable this feature for Konnect commands.
@hbagdi can perhaps answer the "what for" better than I can. We most often use the copies when performing a diff, where we pass a copy to the CRUD creator rather than passing the original object from the target state, though I'm not immediately seeing what the consequences of using the original would be. Copying the linked entities is just adhering to the standard meaning of a deep copy AFAIK: deep copies are recursive and make copies of both the struct you're copying and structs within it. Using the original linked entities means you instead have a shallow copy. On a more practical level, the K8S deepcopy-gen tool fails if you don't include that function and associated tags when you use interfaces like we do here. 653773c, per conversation with Harry:
575c8fa sanitization stuff: as paths are, in practice, just names, I've ditched plans to separate them into directory and filename components and applied an sanitization function to both them and the SP/SV directory names. The sanitization function strips leading path separators and URL-encodes internal path separators. My rationale was:
This isn't perfect: you can create |
Add support for dumping Konnect document entities (https://konnect.konghq.com/docs/ under the "service_packages/:service_package_id/documents" and "service_versions/:service_version_id/documents" headers).
This PR includes changes necessary to implement an initial implementation for handling documents in
deck konnect dump
, including a new document type, logic to pull documents attached to service versions and service packages, state database schema and management for documents, and logic to write document metadata in konnect.yaml and document contents to files on disk.While the UX for this may still change (there are some open questions around how to handle the document file format), I don't expect the innards of the type and state to fundamentally change to support any future UX changes, so IMO this is in a reasonably reviewable state. Targeted to a feature branch off the tip of main. Future UX changes and additional command support (sync/diff/etc.) will go there after before opening a PR to main.