Closed ca-scribner closed 2 years ago
Interesting idea. I was thinking we can make this more reusable and explicit just adding a function to load CDRs from the cluster.
Usage example:
from lightkube import Client
from lightkube import generic_resource as gr
client = Client()
gr.load_in_cluster_generic_resources(client) # here we explicitly load all CRDs, we can also return them
...
with open('deploy.yaml') as f:
codecs.load_all_yaml(f)
Same can be used to get a resource to be used for read/write:
from lightkube import Client
from lightkube import generic_resource as gr
client = Client()
gr.load_in_cluster_generic_resources(client)
CronJob = gr.get_generic_resource("stable.example.com/v1", "Job") # get the class representing this resource.
client.get(CronJob)
Sorry for the slow response.
I like the idea of a function specific for this purpose of loading the cluster's resources, that sounds like a nice helper. And it integrates well with get_generic_resource
as you show.
What about the case where YAML both defines a CRD and then creates a CR for that definition? In that situation, pre-loading the generics will not be enough. The only thing I can think of for that situation is catching the error in the load_all_yaml
and trying to get the CRD from the cluster at that time
Right, for that we can have a parameter as you mention that just create any CRD encountered during load of the YAML stream. Something like:
# load_in_cluster_generic_resources should be called first for resources not defined in the file ...
with open('deploy.yaml') as f:
codecs.load_all_yaml(f, create_missing_resources=True). # whenever a CRD is encountered in the file, it's created if missing.
I've tried to refactor based on your suggestions. What do you think?
All sounds reasonable! I've focused my spare time on the other PR the past few days and will be out of town this week, but will address these suggestions next week. Thanks!
Docs not forgotten but ran out of time today. Will update in the next commit
Good progress! We have few things left:
I was also thinking that we may need an integration test for load_in_cluster_generic_resources()
as it uses the client
. So create a CRD, wait it to be available and call load_in_cluster_generic_resources()
.
Added e2e tests for both regular and async clients and glad you asked because both had bugs :D I was using models
when I should have been using resources
for the CRDs, but I think that is good now. I also noticed that the AsyncClient.list()
method is not async - is that on purpose or a bug? If a bug and it should be async, async_load_in_cluster_generic_resources
will need a minor tweak
Ran into a few problems in the tests where I hit race conditions between the client.delete(crd)
calls of one test and the start of another test, but I think I have those resolved now by just making randomly named CRDs for the tests.
Docs are added now as well. Thanks for all the great feedback!
Changes merged, great work!
AsyncClient.list()
returns an async generator which will start executing once iterating. So iteration requires await
but the call to list
itself doesn't.
ty for the helpful reviews! and makes sense for AsyncClient.list()
, thanks!
Foreward
This PR proposes some convenience for interacting with batches of yaml. I'm not married to the API, etc., and the code does not have a full test suite, but just curious if you're interested in a feature like this and if so what suggestions/requests you have on the API. If you're interested, I'll flesh it out further.
Proposed feature
Sometimes, code might want to apply a YAML file that has CustomResources it might not know about (or might not otherwise need to know about). Currently, we need to instantiate generic resources for these objects before passing their definitions to the cluster for action (say to create an instance of a CustomResource). This proposal tries to make using CustomResources from YAML a bit more convenient by adding an optional
client
argument tocodecs.from_dict
orcodecs.load_all_yaml
. Iffrom_dict
orload_all_yaml
are passed aClient
via this arg, whenever they find an unknown generic resource they try to implicitly load that resource's definition from the cluster. If this does not work, they fail like before. This allows for the application of YAML without needing to know ahead of time what CRs might be defined in the yaml.Implementation details
We
client.list(CustomResourceDefinition)
to look for the resource we are currently missing, creating aGenericResource
for it if found. If aClient
is not provided tocodecs.from_dict
orcodecs.load_all_yaml
, the existing behaviour is unchanged.