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

Fix bug for azurerm_storage_management_policy #5803

Merged

Conversation

neil-yechenwei
Copy link
Contributor

@neil-yechenwei neil-yechenwei commented Feb 18, 2020

This PR is for fixing the issue #4580

Fixes #4580

@ghost ghost added size/XS size/M and removed size/XS labels Feb 18, 2020
@tombuildsstuff tombuildsstuff removed the request for review from mbfrahry February 20, 2020 09:15
Copy link
Member

@jackofallops jackofallops left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @neil-yechenwei
Thanks for the PR. There are few comments indicating changes needed at this stage.

@@ -375,14 +377,20 @@ func flattenStorageManagementPolicyRules(armRules *[]storage.ManagementPolicyRul
if armActionBaseBlob.TierToCool != nil && armActionBaseBlob.TierToCool.DaysAfterModificationGreaterThan != nil {
intTemp := int(*armActionBaseBlob.TierToCool.DaysAfterModificationGreaterThan)
baseBlob["tier_to_cool_after_days_since_modification_greater_than"] = intTemp
} else {
baseBlob["tier_to_cool_after_days_since_modification_greater_than"] = -1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting a "-1" value here will break updates to the resource as this value won't pass validation.

Additionally, flatten should take the same approach as has been done with expand to prevent updates re-introducing the issue being addressed. (an update after creation will set values from state, in this case 0, but should only be added to the state if user configured)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. I already tested. It wouldn't break updates. Could you give me a example?
Below is the test result after updated:
image
image

Here there are two issues.
First issue, the value of property in nested block would be set as "0" for TypeInt when tf config doesn't specify this property. But we actually don't want this is set as 0. We just want this is set as nil. So I have to use this way "d.GetOkExists(fmt.Sprintf("rule.%d.actions.0.base_blob.0.tier_to_archive_after_days_since_modification_greater_than", idx));" to fix this issue.

Second issue, d.set() would set the value of property in nested block as "0" for TypeInt after service api returns nil. Actually we just want this is set as nil. So I have to use this way "baseBlob["tier_to_cool_after_days_since_modification_greater_than"] = -1" to fix this issue.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The above example doesn't exercise your new code where the values are "-1" in the state (i.e. unset by config). If you extend your testing to do something like TestAccAzureRMStorageManagementPolicy_withOneActionWithUpdate and update the single value set in your new test, I believe you should see what I'm referring to. i.e. The update will read -1 from the state for the values not explicitly configured which will fail validation and you'll get something like:

ManagementPolicy rule rule1 is invalid. Invalid value for parameter : daysAfterModificationGreaterThan

To avoid this, we should not d.Set any value if it's not supplied in the config or read back from the API, meaning the approach for traversing the rules with an index value in flatten as you have done for expand is necessary. Does that make sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I repro the issue what you mentioned. But seems that I cannot remove d.Set for the properties since the properties would be set as "null" when the properties aren't specified in tfconfig after removed d.set for these properties. Then it always show the difference when I explicitly update the properties for several times. So I've updated code with other solution. Please help to have a look. If the solution is not better, could you share you sample code for the solution? Thanks.

tfstate result when the properties aren't specified in tfconfig after removed d.set for these properties:

"rule": [
              {
                "actions": [
                  {
                    "base_blob": [
                      {
                        "delete_after_days_since_modification_greater_than": null,
                        "tier_to_archive_after_days_since_modification_greater_than": null,
                        "tier_to_cool_after_days_since_modification_greater_than": null
                      }
                    ],
                    "snapshot": [
                      {
                        "delete_after_days_since_creation_greater_than": 30
                      }
                    ]
                  }
                ],
                "enabled": true,
                "filters": [
                  {
                    "blob_types": [
                      "blockBlob"
                    ],
                    "prefix_match": [
                      "container1/prefix1"
                    ]
                  }
                ],
                "name": "rule1"
              }
            ],

tfconfig for updating this resource several times:

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "test" {
  name     = "acctestRG-storage-neil"
  location = "westus"
}

resource "azurerm_storage_account" "test" {
  name                = "unlikelyneiltest"
  resource_group_name = "${azurerm_resource_group.test.name}"
  location                 = "${azurerm_resource_group.test.location}"
  account_tier             = "Standard"
  account_replication_type = "LRS"
  account_kind             = "BlobStorage"
}

resource "azurerm_storage_management_policy" "test" {
  storage_account_id = "${azurerm_storage_account.test.id}"
  rule {
    name    = "rule1"
    enabled = true
    filters {
      prefix_match = ["container1/prefix1"]
      blob_types   = ["blockBlob"]
    }
    actions {
      base_blob {
        delete_after_days_since_modification_greater_than = 102
      }
      snapshot {
        delete_after_days_since_creation_greater_than = 30
      }
    }
  }
}

Always show the difference while updating this resource several times:
image

}
if armActionBaseBlob.TierToArchive != nil && armActionBaseBlob.TierToArchive.DaysAfterModificationGreaterThan != nil {
intTemp := int(*armActionBaseBlob.TierToArchive.DaysAfterModificationGreaterThan)
baseBlob["tier_to_archive_after_days_since_modification_greater_than"] = intTemp
} else {
baseBlob["tier_to_archive_after_days_since_modification_greater_than"] = -1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above - setting a "-1" value here will break updates to the resource as this value won't pass validation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above reason

}
if armActionBaseBlob.Delete != nil && armActionBaseBlob.Delete.DaysAfterModificationGreaterThan != nil {
intTemp := int(*armActionBaseBlob.Delete.DaysAfterModificationGreaterThan)
baseBlob["delete_after_days_since_modification_greater_than"] = intTemp
} else {
baseBlob["delete_after_days_since_modification_greater_than"] = -1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above - setting a "-1" value here will break updates to the resource as this value won't pass validation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above reason

Comment on lines 70 to 71
resource.TestCheckResourceAttr(data.ResourceName, "rule.0.actions.0.base_blob.0.tier_to_cool_after_days_since_modification_greater_than", "-1"),
resource.TestCheckResourceAttr(data.ResourceName, "rule.0.actions.0.base_blob.0.tier_to_archive_after_days_since_modification_greater_than", "-1"),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned above, these should not be set if not defined by the configuration.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above reason.

@neil-yechenwei
Copy link
Contributor Author

@jackofallops , I'v updated code. Please have a look. THanks.

@jackofallops jackofallops added this to the v2.2.0 milestone Mar 17, 2020
@jackofallops
Copy link
Member

Hi @neil-yechenwei
I hope you don't mind, but we've pushed a couple of updated files to this PR. I didn't seem to be explaining what was needed very well, which led you to revert some of the necessary steps, sorry about that. The changes we've pushed address the correct behaviours required, and still allow the use of 0 values, which are valid for the service. Additionally, when actions are removed from the resource configuration they'll be removed from the resource also. (see the singleActionUpdated test for an example).

Many thanks for your contribution 👍

@jackofallops jackofallops merged commit 9350439 into hashicorp:master Mar 17, 2020
jackofallops added a commit that referenced this pull request Mar 17, 2020
@neil-yechenwei
Copy link
Contributor Author

neil-yechenwei commented Mar 18, 2020

@jackofallops , Thanks for your commit. But I still found a bug from your commit. when the property tier_to_archive_after_days_since_modification_greater_than isn't set in tf config, this property in tfstate file is set as 0. Then I update this tf config and add property tier_to_archive_after_days_since_modification_greater_than = 0. You will see there is no difference after run command "terraform plan". Actually terraform should accept 0 since 0 is meaningful in service side. So it's a bug. Could you help to fix it or can you rollback to my last commit since my commit already fixed this issue?

tfconfig without tier_to_archive_after_days_since_modification_greater_than:

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "test" {
  name     = "acctestRG-storage-neil"
  location = "westus"
}

resource "azurerm_storage_account" "test" {
  name                = "unlikely23exst2acctneil"
  resource_group_name = azurerm_resource_group.test.name

  location                 = azurerm_resource_group.test.location
  account_tier             = "Standard"
  account_replication_type = "LRS"
  account_kind             = "BlobStorage"
}

resource "azurerm_storage_management_policy" "test" {
  storage_account_id = azurerm_storage_account.test.id

  rule {
    name    = "singleActionRule"
    enabled = true
    filters {
      prefix_match = ["container1/prefix1"]
      blob_types   = ["blockBlob"]
    }
    actions {
      base_blob {
        delete_after_days_since_modification_greater_than = 30
      }
      snapshot {
        delete_after_days_since_creation_greater_than = 30
      }
    }
  }
}

tfstate with tier_to_archive_after_days_since_modification_greater_than:

{
  "version": 4,
  "terraform_version": "0.12.21",
  "serial": 4,
  "lineage": "xxxxx",
  "outputs": {},
  "resources": [
    {
      "mode": "managed",
      "type": "azurerm_resource_group",
      "name": "test",
      "provider": "provider.azurerm",
      "instances": [
        {
          "schema_version": 0,
          "attributes": {
            "id": "/subscriptions/xxx-xxx-xxx-xxx/resourceGroups/acctestRG-storage-neil",
            "location": "westus",
            "name": "acctestRG-storage-neil",
            "tags": null,
            "timeouts": null
          },
          "private": "xxxxx"
        }
      ]
    },
    {
      "mode": "managed",
      "type": "azurerm_storage_account",
      "name": "test",
      "provider": "provider.azurerm",
      "instances": [
        {
          "schema_version": 2,
          "attributes": {
            "access_tier": "Hot",
            "account_kind": "BlobStorage",
            "account_replication_type": "LRS",
            "account_tier": "Standard",
            "blob_properties": [],
            "custom_domain": [],
            "enable_https_traffic_only": true,
            "id": "/subscriptions/xxx-xxx-xxx-xxx/resourceGroups/acctestRG-storage-neil/providers/Microsoft.Storage/storageAccounts/unlikely23exst2acctneil",
            "identity": [],
            "is_hns_enabled": false,
            "location": "westus",
            "name": "unlikely23exst2acctneil",
            "network_rules": [
              {
                "bypass": [
                  "AzureServices"
                ],
                "default_action": "Allow",
                "ip_rules": [],
                "virtual_network_subnet_ids": []
              }
            ],
            "primary_access_key": "xxxxx",
            "primary_blob_connection_string": "xxxxxx",
            "primary_blob_endpoint": "https://xxxxx/",
            "primary_blob_host": "unxxxxxt",
            "primary_connection_string": "xxxxxxx",
            "primary_dfs_endpoint": "hxxxxxt/",
            "primary_dfs_host": "unlikely23xxxxx.net",
            "primary_file_endpoint": "",
            "primary_file_host": "",
            "primary_location": "westus",
            "primary_queue_endpoint": "",
            "primary_queue_host": "",
            "primary_table_endpoint": "https://unxxxx.net/",
            "primary_table_host": "unlikely2xxxxows.net",
            "primary_web_endpoint": "",
            "primary_web_host": "",
            "queue_properties": null,
            "resource_group_name": "acctestRG-storage-neil",
            "secondary_access_key": "xxxxxx",
            "secondary_blob_connection_string": "",
            "secondary_blob_endpoint": null,
            "secondary_blob_host": null,
            "secondary_connection_string": "xxxxxxt",
            "secondary_dfs_endpoint": null,
            "secondary_dfs_host": null,
            "secondary_file_endpoint": null,
            "secondary_file_host": null,
            "secondary_location": "",
            "secondary_queue_endpoint": null,
            "secondary_queue_host": null,
            "secondary_table_endpoint": null,
            "secondary_table_host": null,
            "secondary_web_endpoint": null,
            "secondary_web_host": null,
            "static_website": [],
            "tags": null,
            "timeouts": null
          },
          "private": "xxxxxx",
          "dependencies": [
            "azurerm_resource_group.test"
          ]
        }
      ]
    },
    {
      "mode": "managed",
      "type": "azurerm_storage_management_policy",
      "name": "test",
      "provider": "provider.azurerm",
      "instances": [
        {
          "schema_version": 0,
          "attributes": {
            "id": "/subscriptions/xxx-xxx-xxx-xxx/resourceGroups/acctestRG-storage-neil/providers/Microsoft.Storage/storageAccounts/unlikely23exst2acctneil/managementPolicies/default",
            "rule": [
              {
                "actions": [
                  {
                    "base_blob": [
                      {
                        "delete_after_days_since_modification_greater_than": 30,
                        "tier_to_archive_after_days_since_modification_greater_than": 0,
                        "tier_to_cool_after_days_since_modification_greater_than": 0
                      }
                    ],
                    "snapshot": [
                      {
                        "delete_after_days_since_creation_greater_than": 30
                      }
                    ]
                  }
                ],
                "enabled": true,
                "filters": [
                  {
                    "blob_types": [
                      "blockBlob"
                    ],
                    "prefix_match": [
                      "container1/prefix1"
                    ]
                  }
                ],
                "name": "singleActionRule"
              }
            ],
            "storage_account_id": "/subscriptions/xxx-xxx-xxx-xxx/resourceGroups/acctestRG-storage-neil/providers/Microsoft.Storage/storageAccounts/unlikely23exst2acctneil",
            "timeouts": null
          },
          "private": "xxxxxx",
          "dependencies": [
            "azurerm_resource_group.test",
            "azurerm_storage_account.test"
          ]
        }
      ]
    }
  ]
}

update tfconfig to add tier_to_archive_after_days_since_modification_greater_than = 0:

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "test" {
  name     = "acctestRG-storage-neil"
  location = "westus"
}

resource "azurerm_storage_account" "test" {
  name                = "unlikely23exst2acctneil"
  resource_group_name = azurerm_resource_group.test.name

  location                 = azurerm_resource_group.test.location
  account_tier             = "Standard"
  account_replication_type = "LRS"
  account_kind             = "BlobStorage"
}

resource "azurerm_storage_management_policy" "test" {
  storage_account_id = azurerm_storage_account.test.id

  rule {
    name    = "singleActionRule"
    enabled = true
    filters {
      prefix_match = ["container1/prefix1"]
      blob_types   = ["blockBlob"]
    }
    actions {
      base_blob {
	    tier_to_archive_after_days_since_modification_greater_than = 0
            delete_after_days_since_modification_greater_than = 30
      }
      snapshot {
        delete_after_days_since_creation_greater_than = 30
      }
    }
  }
}

Result of "terraform plan":
image

@jackofallops
Copy link
Member

Hi @neil-yechenwei
You are correct - there's a limitation of GetOk I was previously unaware of which does preclude this solution allowing the 0 values that should be allowed. Since the original issue this PR was logged against is addressed by the changes, I will open a new issue to look at addressing the valid zero-value bug.

@ghost
Copy link

ghost commented Mar 19, 2020

This has been released in version 2.2.0 of the provider. Please see the Terraform documentation on provider versioning or reach out if you need any assistance upgrading. As an example:

provider "azurerm" {
    version = "~> 2.2.0"
}
# ... other configuration ...

@ghost
Copy link

ghost commented Apr 16, 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 Apr 16, 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.

Problem to define only one action in azurerm_storage_management_policy
2 participants