-
Notifications
You must be signed in to change notification settings - Fork 232
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
Allow provider to define uniqueness of a resource #224
Comments
(Updated the issue description to include a references section 👍 ) In the Terraform AWS Provider, this functionality would become immensely more helpful if given the availability of both resource configuration value(s) (historically via
Or 1 per provider configuration, such as:
Another consideration may be resources where there can only be 1 per some resource. Sample resources:
Or as another example, 1 per containing resource and name-like identifier, such as:
Hopefully the examples above highlight that determining the uniqueness constraints might be a little more nuanced than a simple field on a single attribute. To put some of the examples into "how these values would be determined in a Create/Read/Update/Delete function manner with ResourceData and the provider interface":
Maybe something conceptually like the below at the resource level could do this? type UniquenessIdentifierFunc func(ResourceData, interface{}) string
type Resource struct {
// UniquenessIdentifier is a string identifier to determine duplicate resource configurations.
// This is globally checked against all other Terraform resources in a single run.
// Any values that cannot be determined at plan time, such as those not known until an upstream
// resource has been applied, this check to be skipped. If the return value is an empty
// string (""), this check will be skipped.
UniquenessIdentifier UniquenessIdentifierFunc
}
// Example in a Terraform AWS Provider resource, such as aws_backup_vault
func PerRegionalNameUniquenessIdentifier(d schema.ResourceData, meta interface{}) string {
return fmt.Sprintf("%s:%s:%s", meta.(*AWSClient).accountid, meta.(*AWSClient).region, d.Get("name").(string))
}
UniquenessIdentifier: PerRegionalNameUniquenessIdentifier,
// Another example in Terraform AWS Provider, such as aws_ebs_default_kms_key
func PerRegionUniquenessIdentifier(d schema.ResourceData, meta interface{}) string {
return fmt.Sprintf("%s:%s", meta.(*AWSClient).accountid, meta.(*AWSClient).region)
}
UniquenessIdentifier: PerRegionUniquenessIdentifier, The nice part here is that it gives resources the freedom to fully synthesize the criteria for uniqueness although it comes at the expense of being a little verbose. The logic checking these would need bypass any with computed attribute values. When writing up the above examples, I found it may make more sense to have the return value be a // Example in a Terraform AWS Provider resource, such as aws_backup_vault
func PerRegionalNameUniquenessIdentifier(d schema.ResourceData, meta interface{}) string {
accountID := meta.(*AWSClient).accountid
if accountID == "" {
return "" // or nil if *string
}
return fmt.Sprintf("%s:%s:%s", accountID, meta.(*AWSClient).region, d.Get("name").(string))
}
UniquenessIdentifier: PerRegionalNameUniquenessIdentifier,
// Another example in Terraform AWS Provider, such as aws_ebs_default_kms_key
func PerRegionUniquenessIdentifier(d schema.ResourceData, meta interface{}) string {
accountID := meta.(*AWSClient).accountid
if accountID == "" {
return "" // or nil if *string
}
return fmt.Sprintf("%s:%s", accountID, meta.(*AWSClient).region)
}
UniquenessIdentifier: PerRegionUniquenessIdentifier, I also wonder if maybe the return value could be something like type UniquenessIdentifierFunc func(ResourceData, interface{}) []string
type Resource struct {
// UniquenessIdentifier is an identifier to determine duplicate resource configurations.
// This is globally checked against all other Terraform resources in a single run.
// If the return value is an empty string ("") for any elements, this check will be skipped.
// Any values that cannot be determined at plan time, such as those not known until an
// upstream resource has been applied, will also cause this check to be skipped.
UniquenessIdentifier UniquenessIdentifierFunc
}
// Example in a Terraform AWS Provider resource, such as aws_backup_vault
func PerRegionalNameUniquenessIdentifier(d schema.ResourceData, meta interface{}) []string {
return []string{
meta.(*AWSClient).accountid,
meta.(*AWSClient).region,
d.Get("name").(string),
}
}
UniquenessIdentifier: PerRegionalNameUniquenessIdentifier,
// Another example in Terraform AWS Provider, such as aws_ebs_default_kms_key
func PerRegionUniquenessIdentifier(d schema.ResourceData, meta interface{}) []string {
return []string{
meta.(*AWSClient).accountid,
meta.(*AWSClient).region,
}
}
UniquenessIdentifier: PerRegionUniquenessIdentifier, Thanks for the consideration! 😄 |
@paddycarver described to me earlier in a separate conversation that it would be helpful in GCP provider to have the ability to validate all occurrences of a given resource type. The main reason was also uniqueness - so I believe the problem definition matches one of this issue. We couldn't really come up with any other reason to run such validation other than to guarantee/validate some form of uniqueness. Paddy mentioned two GCP specific examples:
@paddycarver feel free to add/correct anything above. |
There is a related upstream Terraform Core issue here: hashicorp/terraform#22094 |
Oh! This reminds me of very similar problems we have in the Terraform AWS Provider where there may be two methods for managing a specific piece of infrastructure such as EC2 Security Groups, but using both methods can causes perpetual differences:
In this case the "uniqueness" is even more nuanced since its involves the values of "sub" resources, but the "sub" resources have no identifiers of their own and it actually has nothing to do with overlap either (its matching EC2 Security Group IDs and the I'm wondering if this class of problem should be considered outside the scope of this feature request due to its inherent additional complexity and maybe treated with a different type of solution that can take specific other resource types and their attribute keys/values into consideration. |
Presumably having this information available would make caching of duplicate Data Sources possible too? hashicorp/terraform#19942 |
@tombuildsstuff I would say easier. Due to their nature, data sources may require slightly different approach though. Unlike resources which tend to be managed (and changed) entirely via Terraform, data sources may change outside of Terraform more often and what we consider ID today is far less likely to represent unique state and data sources are expected to always have fresh state. For example you wouldn't want #7 describes an example of how we may address that. Perhaps a combination of these two suggestions will work - labelling fields as "unique combination" (e.g. We'll probably need to check what major APIs support today but I'm guessing some combination of the above will satisfy the majority. |
I no longer have rights in this repository to edit the issue description references again, but please note I've consolidated the various Terraform AWS Provider use cases into hashicorp/terraform-provider-aws#14394. |
Problem Statement
ID field
Each resource today has an ability to set an ID.
This was and to some extent still is treated as a "meta-field" which is special-cased throughout Terraform and SDK, e.g. it has its own getter/setter (
ResourceData.GetId()
,ResourceData.SetId()
), existence of ID was (in Terraform<0.12
) internally used as indicator whether a resource exists or not and it is currently the easiest way to import resources (via their ID) andid
is always available in CRUD but must not be overridden in the schema.ID is however assigned when the resource has either started the process of creation or finished creating (in CRUD). Terraform currently has no way of constructing unique identifier beforehand and therefore no way of predicting whether it will collide with any other unique identifier (it doesn't even attempt to do so for that reason).
Example
DNS is a globally shared namespace and it's possible that in some DNS providers you are able to create duplicate domains for valid reasons (e.g. migration), but often times this is not possible. Route53 will return error for one of the following zones - depending on which one is scheduled for creation 1st while Terraform parallelises requests.
Proposal
Implementation is likely to be subject to RFC & further discussion.
The schema could allow marking certain fields as "identifier", then core would be able to query provider for such enhanced schema and combined with values from the config it should be able to tell if there are any duplicate resources.
(hypothetical) Example
then assuming the HCL config from above
Better and more detailed diagnostic messages are subject to our ability to either display & highlight multiple fields which can make up the identifier or be able to identify the most important one in case there's more than one.
References
The text was updated successfully, but these errors were encountered: