Skip to content

azurerm_data_protection_backup_policy_postgresql: support target_copy property and its related updates#24476

Closed
sinbai wants to merge 11 commits intohashicorp:mainfrom
sinbai:dataprotection/support_new_properties
Closed

azurerm_data_protection_backup_policy_postgresql: support target_copy property and its related updates#24476
sinbai wants to merge 11 commits intohashicorp:mainfrom
sinbai:dataprotection/support_new_properties

Conversation

@sinbai
Copy link
Copy Markdown
Contributor

@sinbai sinbai commented Jan 12, 2024

When supporting targetDataStoreCopySettings property, it was found that TF is currently hard-coded for default azure retention rule and source data store partial value for the lifecycles(Additionally, there is the fact that for the default Azure retention rules/Azure retention rule, the lifecycle may have multiple items instead of the current hard-coded single item). The service team has confirmed that these properties are not immutable. I assume that these properties should be specified by the user.

Therefore, while submitting this PR to support targetDataStoreCopySettings, the original implementation (dependency) was changed and some properties were opened to users.

Test results:
image

  • Bug Fix
  • New Feature (ie adding a service, resource, or data source)
  • Enhancement
  • Breaking Change

Copy link
Copy Markdown
Collaborator

@katbyte katbyte left a comment

Choose a reason for hiding this comment

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

Thanks @sinbai - this looks like the new property won't take affect till 4.0?

is it possible to implement them now inline and support a graceful deprecation path for users instead of the hard breaking change in 4.0? as well allowing them to be used before?

@sinbai
Copy link
Copy Markdown
Contributor Author

sinbai commented Mar 4, 2024

Thanks @sinbai - this looks like the new property won't take affect till 4.0?

is it possible to implement them now inline and support a graceful deprecation path for users instead of the hard breaking change in 4.0? as well allowing them to be used before?

Hi @katbyte thanks for your feedback and sounds like good suggestion. However, the newly added properties default_retention_rule and retention_rule.#.life_cycle should be required properties. If the original required attributes default_retention_duration and retention_rule.#.duration and the new two required are supported at the same time in the 3.0, these two sets of mutually exclusive attributes need to be modified to be optional. Then when the deprecated properties are deleted in the 4.0 , the new properties need to be changed to required. I assume this will be a breaking change (the new properties are changed from optional to required), so I assume this not appropriate, what do you think?

@katbyte
Copy link
Copy Markdown
Collaborator

katbyte commented Mar 5, 2024

Changing something from optional -> required during a major version is just fine! so lets make it optional & enable people using these properties now with the 4.0 flag flipping it to how things should behave in 4.0

@sinbai sinbai force-pushed the dataprotection/support_new_properties branch from 8d946c6 to ed5ce33 Compare March 7, 2024 03:56
@sinbai
Copy link
Copy Markdown
Contributor Author

sinbai commented Mar 7, 2024

Changing something from optional -> required during a major version is just fine! so lets make it optional & enable people using these properties now with the 4.0 flag flipping it to how things should behave in 4.0

Hi @katbyte thanks for your time and feedback. I have updated the code. Could you please take another look? Test results are as follows:
image


---

A `target_copy_setting` block supports the following:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think setting is redundant?

Suggested change
A `target_copy_setting` block supports the following:
A `target_copy` block supports the following:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed.


A `target_copy_setting` block supports the following:

* `copy_option` - (Required) Specifies when the backups are tiered across two or more selected data stores as a json encoded string. Changing this forces a new Backup Policy PostgreSQL to be created.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

and this might be better as

Suggested change
* `copy_option` - (Required) Specifies when the backups are tiered across two or more selected data stores as a json encoded string. Changing this forces a new Backup Policy PostgreSQL to be created.
* `option_json` - (Required) Specifies when the backups are tiered across two or more selected data stores as a json encoded string. Changing this forces a new Backup Policy PostgreSQL to be created.

?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

Comment on lines +37 to +43
"default_retention_duration",
"default_retention_rule.#",
"default_retention_rule.0.%",
"default_retention_rule.0.life_cycle.#",
"default_retention_rule.0.life_cycle.0.%",
"default_retention_rule.0.life_cycle.0.data_store_type",
"default_retention_rule.0.life_cycle.0.duration",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

are these not returned from the API? how come we are ignoring them?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The API returns their values. However, TF supports both default_retention_duration (deprecated in v4.0) and default_retention_rule, which are two mutually exclusive properties in v3.0. These two properties corresponding to the same property of the API. Therefore, when importing resource in v3.0, I assume that we have no way of knowing whether the default_retention_duration or default_retention_rule is specified in the config, so I ignore them. Please see the following code in resourceDataProtectionBackupPolicyPostgreSQLRead func for details. Other than that, could you please let me know if there is a better solution?
image

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

in the past when i have deprecated a property and replaced it with another property i've made them both computed and then just set them both in read so they have a valid property, and then only sent the value that exists/has been set in config off to the api in update/create.

is this possible with these fields to do that?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Hi @katbyte thank you very much, I think this is a very good way. But there is a little problem. If the deprecated and replaced properties are set in read at the same time, then the following checks need to be deleted at the same time. Do you think it's okay to remove the check?
image

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Hi @katbyte a kind reminder in case you miss the above message.

@sinbai
Copy link
Copy Markdown
Contributor Author

sinbai commented Mar 12, 2024

Hi @katbyte I have updated the code to fix the comments above. The test results are as follows, could you please take another look? Thanks for your time.
image

@github-actions
Copy link
Copy Markdown
Contributor

This PR is being labeled as "stale" because it has not been updated for 30 or more days.

If this PR is still valid, please remove the "stale" label. If this PR is blocked, please add it to the "Blocked" milestone.

If you need some help completing this PR, please leave a comment letting us know. Thank you!

@github-actions github-actions Bot added the stale label Apr 15, 2024
@github-actions github-actions Bot removed the stale label May 6, 2024
@github-actions
Copy link
Copy Markdown
Contributor

This PR is being labeled as "stale" because it has not been updated for 30 or more days.

If this PR is still valid, please remove the "stale" label. If this PR is blocked, please add it to the "Blocked" milestone.

If you need some help completing this PR, please leave a comment letting us know. Thank you!

@github-actions github-actions Bot added the stale label Jun 10, 2024
@stephybun
Copy link
Copy Markdown
Contributor

@sinbai having taken another look, this will require some significant rework before this can go in.

Before we go down that path though I have a specific question which is:

Has the request to add support for target_copy come from the service team or is this our own initiative to improve coverage here?

I ask because when creating a Backup Policy for PostgreSQL in the Portal, the option target copy setting isn't exposed at all and there is no way to set that information in the policy currently.

See the JSON excerpt below of the Backup Policy created via the portal:

{
    "properties": {
        "policyRules": [
            {
                "lifecycles": [
                    {
                        "deleteAfter": {
                            "objectType": "AbsoluteDeleteOption",
                            "duration": "P6M"
                        },
                        "targetDataStoreCopySettings": [],
                        "sourceDataStore": {
                            "dataStoreType": "VaultStore",
                            "objectType": "DataStoreInfoBase"
                        }
                    }
                ],
                "isDefault": false,
                "name": "Monthly",
                "objectType": "AzureRetentionRule"

@github-actions github-actions Bot removed the stale label Jul 31, 2024
@sinbai
Copy link
Copy Markdown
Contributor Author

sinbai commented Aug 6, 2024

@sinbai having taken another look, this will require some significant rework before this can go in.

Before we go down that path though I have a specific question which is:

Has the request to add support for target_copy come from the service team or is this our own initiative to improve coverage here?

I ask because when creating a Backup Policy for PostgreSQL in the Portal, the option target copy setting isn't exposed at all and there is no way to set that information in the policy currently.

See the JSON excerpt below of the Backup Policy created via the portal:

{
    "properties": {
        "policyRules": [
            {
                "lifecycles": [
                    {
                        "deleteAfter": {
                            "objectType": "AbsoluteDeleteOption",
                            "duration": "P6M"
                        },
                        "targetDataStoreCopySettings": [],
                        "sourceDataStore": {
                            "dataStoreType": "VaultStore",
                            "objectType": "DataStoreInfoBase"
                        }
                    }
                ],
                "isDefault": false,
                "name": "Monthly",
                "objectType": "AzureRetentionRule"

Hi @stephybun sorry for the late reply. Yes, support for target_copy is a request from the service team. Also, I confirmed with the service team the necessity of this feature support and just received a positive response from them. Regarding the issue of not being visible via Portal, in fact, the feature is visible to some users/ vaults, see the picture below, and they will internally check the reason behind this.
image

@sinbai
Copy link
Copy Markdown
Contributor Author

sinbai commented Nov 7, 2024

@sinbai as 4.0 has been released could we update the PR with 5.0 flags?

addtionally i think the schema can be simplified

Hi @katbyte I have fixed the PR with 5.0 flags. Could you please take another look?

@katbyte
Copy link
Copy Markdown
Collaborator

katbyte commented Nov 7, 2024

@sinbai as per discussed on tuesday here is the breaking change & deprecation guide that this PR should follow: https://github.com/hashicorp/terraform-provider-azurerm/commits/main/contributing/topics/guide-breaking-changes.md

@sinbai
Copy link
Copy Markdown
Contributor Author

sinbai commented Nov 8, 2024

@sinbai as per discussed on tuesday here is the breaking change & deprecation guide that this PR should follow: https://github.com/hashicorp/terraform-provider-azurerm/commits/main/contributing/topics/guide-breaking-changes.md

Hi @katbyte , thanks for your time. I'm assuming I've followed the breaking changes and deprecation guidelines for now, please let me know if I've missed/misunderstood something. Thank you!

Test results in TC:
image

Copy link
Copy Markdown
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 @sinbai - Sorry for the delay on this.

Can you update the title of this PR to reflect the change, it doesn't appear to have anything to do with target_copy_setting, rather you're adding an entire block and deprecating a string property, to add support for target_copy.

Additionally, there are some important points to take a look at below if you could. Once these are addressed, I'll loop back to continue review.

Thanks

Comment on lines +298 to +320
CustomizeDiff: pluginsdk.CustomizeDiffShim(func(ctx context.Context, diff *pluginsdk.ResourceDiff, v interface{}) error {
if !features.FivePointOhBeta() {
retentionRules := diff.Get("retention_rule")
defaultRetentionDuration := diff.Get("default_retention_duration")
defaultRetentionRule := diff.Get("default_retention_rule")

for i, rule := range retentionRules.([]interface{}) {
v := rule.(map[string]interface{})
if v["duration"].(string) == "" && len(v["life_cycle"].([]interface{})) == 0 || v["duration"].(string) != "" && len(v["life_cycle"].([]interface{})) > 0 {
return fmt.Errorf(`one of "retention_rule.%s.duration", "retention_rule.%s.life_cycle" must be specified`, strconv.Itoa(i), strconv.Itoa(i))
}

if defaultRetentionDuration != "" && v["duration"].(string) == "" {
return fmt.Errorf(`"default_retention_duration", "retention_rule.%s.duration" must be specified at the same time`, strconv.Itoa(i))
}

if len(defaultRetentionRule.([]interface{})) > 0 && len(v["life_cycle"].([]interface{})) == 0 {
return fmt.Errorf(`"default_retention_rule", "retention_rule.%s.life_cycle" must be specified at the same time`, strconv.Itoa(i))
}
}
}
return nil
}),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can we move this into the feature flagged block below, it will make it easier and safer to remove after the 5.0 release.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

ForceNew: true,
Computed: true,
ConflictsWith: []string{"default_retention_rule"},
Deprecated: "`default_retention_duration` should be removed in favour of the `default_retention_rule.0.life_cycle.#.duration` property in version 5.0 of the AzureRM Provider.",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Grammar, and formatting as per the deprecation guide.

Suggested change
Deprecated: "`default_retention_duration` should be removed in favour of the `default_retention_rule.0.life_cycle.#.duration` property in version 5.0 of the AzureRM Provider.",
Deprecated: "`default_retention_duration` has been deprecated in favour of the `default_retention_rule.0.life_cycle.#.duration` and will be removed in version 5.0 of the AzureRM Provider.",

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

Optional: true,
ForceNew: true,
Computed: true,
Deprecated: "`retention_rule.#.duration` should be removed in favour of the `retention_rule.#.life_cycle.#.duration` property in version 5.0 of the AzureRM Provider.",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Grammar, and formatting as per the deprecation guide.

Suggested change
Deprecated: "`retention_rule.#.duration` should be removed in favour of the `retention_rule.#.life_cycle.#.duration` property in version 5.0 of the AzureRM Provider.",
Deprecated: "`retention_rule.#.duration` has been deprecated in favour of the `retention_rule.#.life_cycle.#.duration` and will be removed in version 5.0 of the AzureRM Provider.",

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

}),
}

if !features.FivePointOhBeta() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This function has been removed, can you any instances update to use features.FivePointOh() please.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

Comment on lines +387 to +396
if v, ok := d.GetOk("default_retention_duration"); ok && !features.FivePointOhBeta() {
policyRules = append(policyRules, expandBackupPolicyPostgreSQLDefaultAzureRetentionRule(v))
policyRules = append(policyRules, expandBackupPolicyPostgreSQLAzureRetentionRuleArray(d.Get("retention_rule").([]interface{}))...)
} else {
policyRules = append(policyRules, expandBackupPolicyPostgreSQLDefaultRetentionRule(d.Get("default_retention_rule").([]interface{})))
policyRules = append(policyRules, expandBackupPolicyPostgreSQLAzureRetentionRules(d.Get("retention_rule").([]interface{}))...)
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this can be changed to make it easier to remove when 5.0 ships:

Suggested change
if v, ok := d.GetOk("default_retention_duration"); ok && !features.FivePointOhBeta() {
policyRules = append(policyRules, expandBackupPolicyPostgreSQLDefaultAzureRetentionRule(v))
policyRules = append(policyRules, expandBackupPolicyPostgreSQLAzureRetentionRuleArray(d.Get("retention_rule").([]interface{}))...)
} else {
policyRules = append(policyRules, expandBackupPolicyPostgreSQLDefaultRetentionRule(d.Get("default_retention_rule").([]interface{})))
policyRules = append(policyRules, expandBackupPolicyPostgreSQLAzureRetentionRules(d.Get("retention_rule").([]interface{}))...)
}
if !features.FivePointOh() {
if v, ok := d.GetOk("default_retention_duration"); ok {
policyRules = append(policyRules, expandBackupPolicyPostgreSQLDefaultAzureRetentionRule(v))
policyRules = append(policyRules, expandBackupPolicyPostgreSQLAzureRetentionRuleArray(d.Get("retention_rule").([]interface{}))...)
} else {
policyRules = append(policyRules, expandBackupPolicyPostgreSQLDefaultRetentionRule(d.Get("default_retention_rule").([]interface{})))
policyRules = append(policyRules, expandBackupPolicyPostgreSQLAzureRetentionRules(d.Get("retention_rule").([]interface{}))...)
}
} else {
policyRules = append(policyRules, expandBackupPolicyPostgreSQLDefaultRetentionRule(d.Get("default_retention_rule").([]interface{})))
policyRules = append(policyRules, expandBackupPolicyPostgreSQLAzureRetentionRules(d.Get("retention_rule").([]interface{}))...)
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

Comment on lines 440 to 465
if _, ok := d.GetOk("default_retention_duration"); ok && !features.FivePointOhBeta() {
if err := d.Set("default_retention_duration", flattenBackupPolicyPostgreSQLDefaultRetentionRuleDuration(&props.PolicyRules)); err != nil {
return fmt.Errorf("setting `default_retention_duration`: %+v", err)
}
if err := d.Set("retention_rule", flattenBackupPolicyPostgreSQLRetentionRuleArray(&props.PolicyRules)); err != nil {
return fmt.Errorf("setting `retention_rule`: %+v", err)
}
} else {
if err := d.Set("default_retention_rule", flattenBackupPolicyPostgreSQLDefaultRetentionRule(&props.PolicyRules)); err != nil {
return fmt.Errorf("setting `default_retention_rule`: %+v", err)
}
if err := d.Set("retention_rule", flattenBackupPolicyPostgreSQLRetentionRules(&props.PolicyRules)); err != nil {
return fmt.Errorf("setting `retention_rule`: %+v", err)
}
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This will break importing the resource in almost all cases (which is why you had to ignore more or less everything in the test below). This will need to be reworked to allow those tests to pass correctly without ignoring the import errors.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

func TestAccDataProtectionBackupPolicyPostgreSQL_basic(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_data_protection_backup_policy_postgresql", "test")
r := DataProtectionBackupPolicyPostgreSQLResource{}
if !features.FivePointOhBeta() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

These tests need to be split into 4.x and 5.0 versions, since they have differing functionality, and currently they will require significant effort to resolve/make right when 5.0 ships.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

@sinbai sinbai changed the title azurerm_data_protection_backup_policy_postgresql: support target_copy_setting property azurerm_data_protection_backup_policy_postgresql: support target_copy property and its related updates Feb 19, 2025
@sinbai
Copy link
Copy Markdown
Contributor Author

sinbai commented Feb 19, 2025

Hi @sinbai - Sorry for the delay on this.

Can you update the title of this PR to reflect the change, it doesn't appear to have anything to do with target_copy_setting, rather you're adding an entire block and deprecating a string property, to add support for target_copy.

Additionally, there are some important points to take a look at below if you could. Once these are addressed, I'll loop back to continue review.

Thanks

Hi @jackofallops thanks for your feedback. I have updated the code, could you please take another look?

@teowa
Copy link
Copy Markdown
Collaborator

teowa commented Apr 9, 2026

Close this as azurerm_data_protection_backup_policy_postgresql has been deprecated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies documentation enhancement service/analysis service/api-management service/app-configuration service/app-service service/application-insights service/arc-kubernetes service/attestation service/authorization service/automation service/azure-stack-hci service/batch service/cdn service/cognitive-services service/communication service/connections service/consumption service/container-apps service/cosmosdb service/cost-management service/data-factory service/data-protection service/databox-edge service/databricks service/dev-center service/digital-twins service/dns service/dynatrace service/elastic service/event-grid EventGrid service/event-hubs EventHubs service/fabric service/firewall service/hdinsight service/healthcare service/hybrid-compute service/iot-central service/iot-hub service/key-vault Key Vault service/kusto service/load-balancers service/load-test service/log-analytics service/logic service/machine-learning service/maintenance service/managed-apps service/managed-hsm service/management-groups service/maps service/mixed-reality service/mongo-cluster service/monitor service/mssql Microsoft SQL Server service/mssqlmanagedinstance service/mysql service/netapp service/network service/network-function service/nginx service/orbital service/paloalto service/policy service/postgresql service/power-bi service/recovery-services service/redis service/search service/security-center service/sentinel service/service-bus service/signalr service/spring service/storage service/stream-analytics service/synapse service/traffic-manager service/trustedsigning service/video-indexer service/virtual-desktops size/XL state-migration tooling waiting-response

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants