-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
Filter out from properties of tags object. #1107
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.
hi @metacpp
Thanks for this PR - as far as I know the $type
tag is valid/could be used by users in other scenarios, as such can we filter this out just in the explicit resource where it needs to be filtered out? In addition can we add some (acceptance & unit) tests to verify this works as intended
Thanks!
azurerm/tags.go
Outdated
// Filter out $type from tags object to avoid unexpected change on plan. | ||
if i != "$type" { | ||
output[i] = *v | ||
} |
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 think it's best to filter this on the individual resource where this needs to be filtered out (as people may have a legitimate use for the $type
tag) - can we instead filter this out on the resource before calling this function? e.g.
tagsToOutput := make([]string, 0)
for i, v := range resp.Tags {
tag = *v
// Filter out $type from tags object to avoid unexpected change on plan.
if tag != "$type" {
tagsToOutput[i] = tag
}
}
in addition - can we add some validation to ensure that the $type
tag can't be added on that resource? We can do this using a ValidateFunc
on the tags
schema item for this resource :)
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've updated the code and tests.
…n logic to avoid $type from end user as tag name.
@tombuildsstuff The PR is updated and I will share test results later. |
azurerm/tags.go
Outdated
for i, v := range tagsMap { | ||
output[i] = *v | ||
if !strings.EqualFold(i, skipPropName) { |
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.
Why using case insensitive comparison instead of "==" operator 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.
"$type" seems to be reserved usage in PLAN, it should be case insensitive. Or, to be safer, we should use case sensitive 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.
👍 for it being case insensitive
azurerm/tags.go
Outdated
if tagsMap == nil { | ||
d.Set("tags", make(map[string]interface{})) | ||
return | ||
} | ||
|
||
output := make(map[string]interface{}, len(tagsMap)) | ||
|
||
// Only first optional parameter will be processed. |
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 about the rest of the parameters?
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.
This is going to support optional parameter. A better way is to build a map instead. Let me refactor the code.
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.
let's instead revert the changes to this method entirely and leave it in the single resource where this change is needed - this method's already doing too much
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.
hey @metacpp
Thanks for pushing those updates. Given this change is only needed in a single place (and the flattenAndSetTags
method is already doing too much) - can we revert the changes to this method and instead limit the filtering of tags so that it's done within the resourceArmMetricAlertRuleRead
method? I've left an example of what I mean for this in the review comments
Thanks!
@@ -276,7 +276,7 @@ func resourceArmMetricAlertRuleRead(d *schema.ResourceData, meta interface{}) er | |||
d.Set("webhook_action", webhook_actions) | |||
} | |||
|
|||
flattenAndSetTags(d, resp.Tags) | |||
flattenAndSetTags(d, resp.Tags, "$type") |
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.
this function's already doing too much as it is - can we filter out the tags to remove before passing this in? e.g.
tagsToOutput := make([]string, 0)
for k, v := range resp.Tags {
if strings.EqualFold(k, "$type") {
continue
}
tagsToOutput[k] = v
}
flattenAndSetTags(d, tagsToOutput, "$type")
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.
To be honest, I don't quite understand why the filtering logic breaks the KISS principle. Anyway, I moved the filtering logic into a utility function supporting tag list. If in the near future, any other resource needs to filter out any tags, it can reuse the logic instead of another copy and paste.
@@ -34,6 +34,7 @@ func TestAccAzureRMMetricAlertRule_virtualMachineCpu(t *testing.T) { | |||
Check: resource.ComposeTestCheckFunc( | |||
testCheckAzureRMMetricAlertRuleExists(resourceName), | |||
resource.TestCheckResourceAttr(resourceName, "enabled", "false"), | |||
resource.TestCheckNoResourceAttr(resourceName, "$type"), |
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.
this is looking for the field $type
rather than the Tag $type
- as such this won't work. Instead this wants to check for tags.$type
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.
Good catch.
@@ -54,6 +55,7 @@ func TestAccAzureRMMetricAlertRule_sqlDatabaseStorage(t *testing.T) { | |||
Config: config, | |||
Check: resource.ComposeTestCheckFunc( | |||
testCheckAzureRMMetricAlertRuleExists(resourceName), | |||
resource.TestCheckNoResourceAttr(resourceName, "$type"), |
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.
this is looking for the field $type
rather than the Tag $type
- as such this won't work. Instead this wants to check for tags.$type
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.
Good catch.
azurerm/tags.go
Outdated
if tagsMap == nil { | ||
d.Set("tags", make(map[string]interface{})) | ||
return | ||
} | ||
|
||
output := make(map[string]interface{}, len(tagsMap)) | ||
|
||
// Only first optional parameter will be processed. |
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.
let's instead revert the changes to this method entirely and leave it in the single resource where this change is needed - this method's already doing too much
Updated the PR and reran the related tests without any regression: === RUN TestAccAzureRMMetricAlertRule_sqlDatabaseStorage Kicked off another comprehensive testing on Teamcity. |
azurerm/tags.go
Outdated
@@ -56,6 +57,10 @@ func validateAzureRMTags(v interface{}, k string) (ws []string, es []error) { | |||
es = append(es, fmt.Errorf("the maximum length for a tag key is 512 characters: %q is %d characters", k, len(k))) | |||
} | |||
|
|||
if strings.EqualFold(k, "$type") { | |||
es = append(es, fmt.Errorf("the %q is not allowed as tag name", k)) | |||
} |
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.
given this method is shared across all tags (and this validation is only specific to the metrics_alertrule
resource) - can we make a specific validation method for the that resource? we can call the main validation function, and then check that $type
isn't included?
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.
Interesting, it seems that this file is inconsistent between local and remote. Let me check it and refresh it.
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.
@tombuildsstuff
I did some investigation for $type while using it in tag naming for metric_alertrule resource:
- You can't directly use $type as naming of key in TF, you need to use "$type".
- "$type" is not acceptable by API:
Error: Error applying plan:
1 error(s) occurred:
* azurerm_metric_alertrule.critical_cpu: 1 error(s) occurred:
* azurerm_metric_alertrule.critical_cpu: insights.AlertRulesClient#CreateOrUpdate: Failure responding to request: StatusCode=400 -- Original Error: autorest/azure: Service returned an error. Status=400 Code="UnsupportedRequestContent" Message="Request content is not well formed or supported."
In general, I feel that $type is not supposed as customized naming, it's reserved for internal usage, no matter from TF or Azure ARM API.
I understand that you're worried that we're forcing TF user to follow a more strict naming for all the resources, but, it also introduces inconsistency among all the resources. User will get confuse that sometimes it's allowed to use "$type" as tag name, the other times it's not allowed for some "unknown" story.
If we still want to limit the change for this special resource, we will need to create a new tag schema instead. Please see my updated PR, I don't it's worth taking this change.
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.
That's true for this specific API but isn't the case across the whole of Azure, for instance I'm able to create a resource with $type
as the key (note: this is double-escaped for HCL):
resource "azurerm_resource_group" "test" {
name = "tharvey-dev3"
location = "West US"
tags {
"$$type" = "hi"
}
}
in the case where this value isn't allowed we'll add validation logic to Terraform to the specific resources to handle this - but in general the key $type
is a permitted value and as such we shouldn't obstruct that across the board.
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.
Please review my latest change, it seems that even if the PR is updated, the comment is still shown on old commit.
…on and scope it only for metric alert rule.
Added one unit test and ran it successfully. |
@tombuildsstuff does it look good to you for this PR? |
@tombuildsstuff ran all the related tests and passed. |
``` $ acctests azurerm TestValidateMetricAlertRuleTags === RUN TestValidateMetricAlertRuleTags --- PASS: TestValidateMetricAlertRuleTags (0.00s) PASS ok github.com/terraform-providers/terraform-provider-azurerm/azurerm 0.025s ```
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'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. If you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. If you feel I made an error 🤖 🙉 , please reach out to my human friends 👉 hashibot-feedback@hashicorp.com. Thanks! |
This PR is used to fix #945 while running
terraform plan
afterterraform apply
due to "$type" in the tags property map.