-
Notifications
You must be signed in to change notification settings - Fork 914
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
One-pager for Managed Resources API Patterns #840
Conversation
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.
Thanks for getting started on this @muvaf! I added a few initial thoughts.
https://docs.google.com/document/d/10MrgDAw9r22swcX7yCptRWmxU7dcndgql8_6nZfSL5U/edit#
I also updated the above document in which I've tried to compile a list of all the potential changes that have been bouncing around over the last few weeks. We definitely do not need to tackle all of them, but I think naming external resources and immutable spec fields could be in scope for this document.
@negz Thanks for pointing out that document! I've made additions but I didn't want to touch all of the topics as I want this document to be more about the steps where the developer tries to develop the parts of the managed resource that is related to the relation between provider's API and our managed reconciler. For example, naming or high fidelity depend on the resource/API you call but reclaim policy is generic for all managed resources. The parts that appear in the Google doc but are not included in this document:
|
If we are able to provide a name, the decision flow is as following: | ||
|
||
1. Use CR name if the provider allows 253 characters for resource name. If not: | ||
2. Write your own name generation format with a random string generator that you can be sure the generated 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.
What if:
- the provider auto-generates unique names (
foo12345
,foo-adjective-animal
) - the provider lets you supply a name
- the character max is less than 253
I think this may be a common case worth included in this ruleset. With a CSI PVC driver, I truncated the PVC name for use as the provider label, but in that particular case there was no auto-generated name from the provider.
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.
How about this; as long as resourceType+UID
is less than what's allowed by the provider, use it. If it's longer that allowed, do not cut the tail, implement your own random generator for UID part whose length is suitable.
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.
Thanks for patiently waiting for feedback on this @muvaf! It's been a long week of planning meetings and reviews. 😓
I want this document to be more about the steps where the developer tries to develop the parts of the managed resource that is related to the relation between provider's API and our managed reconciler.
That makes sense. I do think we'll need to somehow tie the topics touched on in this document together with those covered in others (e.g. dependencies, reclaim policy) to make sure everything makes sense as a consistent whole. I believe @bassam suggested it would be a good idea to write up example YAMLs representing our ideal of how various Crossplane resources would be shaped. That's probably something we should do separately to this document.
If there is a reference to another provider API object (the object could be a tree of other objects like in Azure), only | ||
include the provider's identifier of that object to make it easier to query it when needed. Trying to include the whole | ||
tree can even go to the state where all your setup that is connected to each other is represented under one resource's | ||
status, which is a very bad UX. |
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.
My understanding is that we may need to make a recommendation around this Azure-ish case for spec inputs as well as status outputs. Two examples of this are:
- Creating or updating an Azure virtual network. The Azure API allows you to specify a set of subnets and peerings that also exist as distinct Azure API objects and thus could be modeled as distinct managed resources.
- Creating or updating a GKE cluster. The API allows you to provide a set of node pools, that also exist as distinct GKE API objects and thus could be modeled as distinct managed resources.
Perhaps Crossplane should take a stance something like "if this external resource could be CRUD as either a subfield of a parent resource or as a distinct resource, Crossplane supports only the latter". So basically we'd omit the nodePools
of a GKE cluster managed resource and instead require you to create distinct node pool managed resources instead.
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.
if this external resource could be CRUD as either a subfield of a parent resource or as a distinct resource, Crossplane supports only the latter
I thought about this a lot and I think we might have to do this way even though we want to support referring resources that are not managed by the given Crossplane instance or Crossplane has no support for that resource type yet.
Let's say we created a struct that has identification information of []*SubnetReference and included this as a field in Azure VirtualNetwork to support adding non-Crossplane-managed Subnet resource.
type VirtualNetwork struct {
subnets []*SubnetReference
}
I created a VirtualNetwork object with this array having a subnet named A
. Azure will create the VirtualNetwork and the Subnet A
. Then I went ahead and created an actual Subnet CR with subnet name B
that refers to my VirtualNetwork. In that case my desired state about how VirtualNetwork's subnets should be constructed is divided; virtual network controller will delete B
since it sees the desired state of VirtualNetwork having only A
subnet, on the other hand, subnet controller will say B
who refers to my VirtualNetwork should exist. So, possibly, one will delete and the other one will create.
In the current implementation, VirtualNetwork object doesn't mention any Subnet at all. So, the desired state of Subnet part of the VirtualNetwork is managed only by our Subnet resource and that is consistent. So, I guess we'll either expand VirtualNetwork resource to make it the only way of creating Subnets or we will eliminate other resource references in it.
We can expand VirtualNetwork and remove Subnet, but we don't know where this might end. It can be a really long tail of resources provisioned in only one CR. So, we might have to take that stance where we say you have to create a CR for that sub-resource if we have support for it. I think having external resource policy read-only mode(crossplane/crossplane-runtime#22 (comment)) will help users to add resource only for reference purposes even though they don't want to manage them with Crossplane or with that Crossplane instance.
I think this analogy applies to GKE node pools as well.
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 thing that came up when syncing with @muvaf on this topic was that, as mentioned, we are currently ignoring the embedded Subnet
slice on the Azure VirtualNetwork
, so adding a subnet via a Subnet
custom resource does not cause the VirtualNetwork
controller to update the VirtualNetwork
. However, I am concerned that if some other part of the VirtualNetwork
changes that causes the controller to update, that it may delete any subnets that were created. The subnets would then be recreated by the Subnet
controller, but it could have some pretty severe negative effects on other resources. It is possible that the Azure API will not delete subnets if update is called on a virtual network, but I am not certain. I am going to test this out today.
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.
@muvaf @negz I confirmed this behavior and have opened an issue to track crossplane-contrib/provider-azure#23
update `Spec` and input user should make changes on that current value of the field. Related to https://github.com/crossplaneio/crossplane-runtime/issues/10 | ||
|
||
What goes into `Status`: | ||
Does the provider give the information of that field on the first level of the query, `GET`? |
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.
Are you still thinking this would be a superset of the spec? i.e. That we'd include the current observed state of all spec fields in case they diverged from the spec? I think that's implied here, but I think it may be worth making it explicit given that it's an uncommon pattern.
(FWIW I'm still super on the fence about whether we should do this.)
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.
Ah - I see this is covered below in immutable properties but I still think it's worth pointing out out 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.
As long as we can come up with something else that covers the following cases, I'd be more than happy to change that.
- It should be sufficient to allow access to
Status
sub-resource(via RBAC) for all-purpose information extraction by other entities. Meaning, I would like to be able to extract the current settings, identification information, metadata etc. only by looking atStatus
. - We need to represent the most up-to-date state in happy cases as well as error cases. If user changed the desired state and if we are in the middle of applying it/couldn't apply it/never plan to apply it, the user should be able to know get the current state even if no error shows up. If we have an update-able config only in
Spec
, we're not able to do that.
However, we can also discuss the need for two points mentioned here. For instance, if we decide the first one is not worth covering, we can remove the creation-time and metadata fields from Status
and keep only update-able fields and identification fields(for references) there.
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.
Give there's a solid technical reason to do this, but that it's an uncommon pattern for Kubernetes, I suggest we avoid doing it for the time being but make sure there's an issue tracking the idea. We can then implement this if the main problem we foresee (hidden drift between the desired and actual state) becomes a real issue based on user 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.
Opened #925
Makes sense. What we could do is maybe have a design doc that has summary of every feature managed resources have in one paragraph and then link to the related one-pager/design doc/issue for details about that specific feature.
I believe if we refactor one or two managed resources to adopt this pattern, then we can easily point to them and also use their YAMLs in the documents. After merging this, I'll open issues for that refactoring effort. I tried to add example snippets to this document anyway. @negz Thanks a lot for your thorough review! I have made the necessary changes and answered your comments. |
Tries to solve consistency issue between many managed resources. Signed-off-by: Muvaffak Onus <onus.muvaffak@gmail.com>
Signed-off-by: Muvaffak Onus <onus.muvaffak@gmail.com>
@negz That's how it'd look like in an example resource crossplane-contrib/provider-gcp#41 Here is creation YAML:
After the reconciliation:
Note how |
@negz updated with the alignment that we landed on with you and bassam. |
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.
There are a few open comments from @soorena776 and myself that I think are worth addressing, but this is pretty much good to go. Let me know once you feel everything is addressed and I'll merge. Thanks for driving this complicated effort!
…ideration. Signed-off-by: Muvaffak Onus <onus.muvaffak@gmail.com>
@negz I think this is ready to merge! |
Description of your changes
This one-pager serves as ground for the discussions that will hopefully get us closer to having a consistent managed resource API.
I think that we should aim to make implementation of managed resources as mechanical as possible. This guide will serve as starting point on how we want things to look like even if we do/don't have code-generation sometime in the future.
Fixes #831, #728
Checklist
I have:
make reviewable
to ensure this PR is ready for review.clusterrole.yaml
to include any new types.