-
Notifications
You must be signed in to change notification settings - Fork 89
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
Support initProvider #237
Support initProvider #237
Conversation
Checked the size change for the CRDs in providers provider-aws - ~15% ~/go/provider-aws/package (main) [stash: 1]$ du -sh crds
27M crds
~/go/provider-aws/package (granular_management_policies) [stash: 1]$ du -sh crds
31M crds provider-gcp - ~23% ~/go/provider-gcp/package (main) $ du -sh crds
13M crds
~/go/provider-gcp/package (gmp) $ du -sh crds
16M crds provider-azure - 16% ~/go/provider-azure/package (main) $ du -sh crds
25M crds
~/go/provider-azure/package (gmp) $ du -sh crds
29M crds |
@lsviben it is getting complicated, and I am a bit lost with when (i.e. managementPolicy) we use which (required/optional vs CEL) validation on where ( |
I updated the description of the issue, I hope it makes more sense now. |
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.
LGTM, except I want to make sure to minimize the diff caused by this PR by putting // +kubebuilder:validation:Optional
markers back as I stated 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.
Thank you @lsviben for working on this feature. Left some comments to capture some of the offline discussions we had and some suggestions for you consider. None is blocking from my perspective.
ForProviderType *types.Named | ||
AtProviderType *types.Named | ||
ForProviderType *types.Named | ||
InitProviderType *types.Named |
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.
Not for this PR, but should we consider putting the generation of the spec.initProvider
API behind a configuration parameter (make the generation of the API optional)?
How do we feel about the following question? Will all the providers generated by upjet need this API on their MRs? From our previous discussions, my understanding is that not every MR (or provider in the higher level) may need this API. If this is the case, then we can consider opening an issue in upjet so that we can parameterize the code generation pipeline.
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 would say that probably because of tags it will be needed for all resources. But as an alpha feature we can see how it is used. We could add a configuration parameter not to generate initProviders for some fields, and just put an empty struct for.
Signed-off-by: lsviben <[email protected]>
Description of your changes
Adds support for the new
initProvider
alpha feature, which is a part of the managementpolicies feature (design)
Runtime changes
As Upjet uses Terraform, it needs to create the
main.tf
file and workspace to run commands against it. It does it in the Connect step of the managed reconciler. The creation of the workspace already fills up the main.tf with the resource in question. This means that in the Create and Update steps the passed resource is not actually the one which we Create/Update, as it has already been set in theConnect
. This means that at the point of creating themain.tf
file, we dont know if it will be used for Update or Create. So to fulfill the purpose ofinitProvider
which is to have fields that are only used during Create, we need to use available TF tools - ignore_changes lifecycle hook, to mark the fields which should only be used for creation.So if the management policies are enabled, when creating the FileProducer that holds the parameters of the
main.tf
file:ignore_changes
by going through thespec.initProvider
andspec.forProvider
, and looking for fields set inspec.initProvider
but not inspec.forProvider
spec.initProvider
tospec.forProvider
TODO:
currently
spec.initProvider
fields overwrite thespec.forProvider
fields if both are set (slices and maps merge), due to how mergo works. In practice, this will be a problem if the user tries to set a field/map key in both. For our current use cases we dont have this situation, and it can be resolved easily by removing theinitProvider
conflicting key if the user wants to useforProvider
for it. But we should take a look and fix that.Issue: #240
Code generation
As mentioned in the design, added a new field in the resource
spec
,spec.initProvider
. It will be used to set some fields of thespec.forProvider
which should be used just in Create. We are not copyingspec.forProvider
1:1 because some field types are not suited to be replaced during Create.The code generation recognizes a few different field types, based on resource config or terraform API information:
region
. Configured by provider optionsFor
initProvider
we are just interested in the Regular fields. Because:region: us-west-1
and expect to later managed it inus-east-3
.tf: "-"
tag. Its the fields above, but added it for precaution, as we are merging initProvider and forProvider and calculatingignore_changes
based on the terraform fields.We could in theory add reference and sensitive fields to the
initProvider
but as there is not use case for that and their usage could incur bugs, I would rather leave them out unless they are needed.CEL rules
All required
spec.forProvider
fields, which are alsospec.initProvider
fields are now optional, because they can be replaced withinitProvider
fields. We already have a functionality to mark the top non-identifier required fields as optional and set CEL rules to check if they are set, or if ObserveOnly managementPolicy is active. This only affects the top level fields, as it can easily mark required nested structs.// +kubebuilder:validation:XValidation:rule="!('*' in self.managementPolicies || 'Create' in self.managementPolicies || 'Update' in self.managementPolicies)",message="%s is a required parameter"
Now because of initProvider, we can also check if the field is in
spec.initProvider
// +kubebuilder:validation:XValidation:rule="!('*' in self.managementPolicies || 'Create' in self.managementPolicies || 'Update' in self.managementPolicies || has(self.forProvider.%s))",message="%s is a required parameter"
But because now we merge required nested structs from
spec.initProvider
tospec.forProvider
we need to expand the CEL rules to also mark the nested fields as required either inspec.initProvider
orspec.forProvider
. This is something still TODO, issue: #239.Fixes #225
I have:
make reviewable
to ensure this PR is ready for review.backport release-x.y
labels to auto-backport this PR if necessary.How has this code been tested
The generation code has been tested with generating provider aws
Tested with provider-aws(PR), creating a Node Group from the design example.
with some added fields to test the ignore_changes generation:
Resulting
main.tf.json
:DynamoDB Table