Skip to content
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

Merged
merged 11 commits into from Apr 20, 2018
Merged

Conversation

metacpp
Copy link
Contributor

@metacpp metacpp commented Apr 10, 2018

This PR is used to fix #945 while running terraform plan after terraform apply due to "$type" in the tags property map.

@metacpp metacpp added this to the 1.3.3 milestone Apr 10, 2018
@metacpp metacpp self-assigned this Apr 10, 2018
Copy link
Member

@tombuildsstuff tombuildsstuff left a 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
}
Copy link
Member

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 :)

Copy link
Contributor Author

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.

@metacpp
Copy link
Contributor Author

metacpp commented Apr 10, 2018

@tombuildsstuff The PR is updated and I will share test results later.

@metacpp
Copy link
Contributor Author

metacpp commented Apr 10, 2018

Most of failed tests are due to long running, the others has nothing to do with code change.

screen shot 2018-04-10 at 9 28 49 pm

azurerm/tags.go Outdated
for i, v := range tagsMap {
output[i] = *v
if !strings.EqualFold(i, skipPropName) {
Copy link

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?

Copy link
Contributor Author

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.

Copy link
Member

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.
Copy link

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?

Copy link
Contributor Author

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.

Copy link
Member

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

Copy link
Member

@tombuildsstuff tombuildsstuff left a 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")
Copy link
Member

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")

Copy link
Contributor Author

@metacpp metacpp Apr 17, 2018

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"),
Copy link
Member

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

Copy link
Contributor Author

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"),
Copy link
Member

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

Copy link
Contributor Author

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.
Copy link
Member

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

@metacpp
Copy link
Contributor Author

metacpp commented Apr 17, 2018

Updated the PR and reran the related tests without any regression:

=== RUN TestAccAzureRMMetricAlertRule_sqlDatabaseStorage
--- PASS: TestAccAzureRMMetricAlertRule_sqlDatabaseStorage (204.23s)
PASS
=== RUN TestAccAzureRMMetricAlertRule_importVirtualMachineCpu
--- PASS: TestAccAzureRMMetricAlertRule_importVirtualMachineCpu (500.87s)
PASS
=== RUN TestAccAzureRMMetricAlertRule_virtualMachineCpu
--- PASS: TestAccAzureRMMetricAlertRule_virtualMachineCpu (560.33s)
PASS
ok ../azurerm/test-azurerm 560.355s

Kicked off another comprehensive testing on Teamcity.

@tombuildsstuff tombuildsstuff modified the milestones: 1.3.3, 1.4.0 Apr 17, 2018
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))
}
Copy link
Member

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?

Copy link
Contributor Author

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.

Copy link
Contributor Author

@metacpp metacpp Apr 17, 2018

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:

  1. You can't directly use $type as naming of key in TF, you need to use "$type".
  2. "$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.

Copy link
Member

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.

Copy link
Contributor Author

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.

@metacpp
Copy link
Contributor Author

metacpp commented Apr 17, 2018

Added one unit test and ran it successfully.
=== RUN TestExpandARMTags
--- PASS: TestExpandARMTags (0.00s)

@metacpp
Copy link
Contributor Author

metacpp commented Apr 18, 2018

@tombuildsstuff does it look good to you for this PR?

@metacpp metacpp requested a review from paultyng April 18, 2018 18:56
@tombuildsstuff tombuildsstuff removed the request for review from paultyng April 19, 2018 10:10
@metacpp
Copy link
Contributor Author

metacpp commented Apr 19, 2018

screen shot 2018-04-19 at 9 45 08 am

@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
```
Copy link
Member

@tombuildsstuff tombuildsstuff left a 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 pushing those updates. @metacpp I've pushed a commit to refactor this to match the other conventions but this otherwise now LGTM 👍 df7c9e7

Thanks!

@tombuildsstuff
Copy link
Member

Tests pass:

screen shot 2018-04-20 at 17 22 21

@tombuildsstuff tombuildsstuff merged commit ebba5af into master Apr 20, 2018
@tombuildsstuff tombuildsstuff deleted the fix_alertrule branch April 20, 2018 15:47
tombuildsstuff added a commit that referenced this pull request Apr 20, 2018
@ghost
Copy link

ghost commented Mar 31, 2020

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!

@hashicorp hashicorp locked and limited conversation to collaborators Mar 31, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Azurerm_metric_alertrules tag $type is treated as changed after apply
3 participants