Skip to content

New Resource: azurerm_durable_task_scheduler, azurerm_durable_task_hub, azurerm_durable_task_retention_policy & New Data Source: azurerm_durable_task_scheduler#32194

Open
stemaMSFT wants to merge 22 commits intohashicorp:mainfrom
stemaMSFT:feature/durable-task-service-v2
Open

New Resource: azurerm_durable_task_scheduler, azurerm_durable_task_hub, azurerm_durable_task_retention_policy & New Data Source: azurerm_durable_task_scheduler#32194
stemaMSFT wants to merge 22 commits intohashicorp:mainfrom
stemaMSFT:feature/durable-task-service-v2

Conversation

@stemaMSFT
Copy link
Copy Markdown
Collaborator

@stemaMSFT stemaMSFT commented Apr 16, 2026

Community Note

  • Please vote on this PR by adding a 👍 reaction to the original PR to help the community and maintainers prioritize for review
  • Please do not leave comments along the lines of "+1", "me too" or "any updates", they generate extra noise for PR followers and do not help prioritize for review

Description

This PR adds support for the Azure Durable Task Framework service with the following new resources and data source:

New Resources:

  • azurerm_durable_task_scheduler — Manages a Durable Task Scheduler, supporting Consumption and Dedicated SKUs, IP allow lists, and tagging.
  • azurerm_durable_task_hub — Manages a Task Hub within a Durable Task Scheduler.
  • azurerm_durable_task_retention_policy — Manages the retention policy for a Durable Task Hub, configuring automatic purge of orchestration history.

New Data Source:

  • azurerm_durable_task_scheduler — Reads an existing Durable Task Scheduler resource.

All resources use hashicorp/go-azure-sdk typed resources with the durabletask/2025-04-01-preview API version.

PR Checklist

  • I have followed the guidelines in our Contributing Documentation.
  • I have checked to ensure there aren't other open Pull Requests for the same update/change.
  • I have checked if my changes close any open issues. If so please include appropriate closing keywords below.
  • I have updated/added Documentation as required written in a helpful and kind way to assist users that may be unfamiliar with the resource / data source.
  • I have used a meaningful PR title to help maintainers and other users understand this change and help prevent duplicate work.
    For example: "resource_name_here - description of change e.g. adding property new_property_name_here"

New Resource / Data Source

This PR introduces a new service package (durabletask) with three resources and one data source.

  • I have added an explanation of what my changes do and why I'd like you to include them (This may be covered by linking to an issue above, but may benefit from additional explanation).
  • I have written new tests for my resource or datasource changes & updated any relevant documentation.
  • I have successfully run tests with my changes locally. If not, please provide details on testing challenges that prevented you running the tests.

Testing

  • My submission includes Test coverage as described in the Contribution Guide and the tests pass.
image

Acceptance tests cover:

  • TestAccDurableTaskSchedulerResource_basic — Create/destroy lifecycle
  • TestAccDurableTaskSchedulerResource_requiresImport — Import detection
  • TestAccDurableTaskSchedulerResource_complete — All optional properties
  • TestAccDurableTaskSchedulerResource_update — In-place update (tags, IP allow list)
  • TestAccDurableTaskHubResource_basic — Create/destroy lifecycle
  • TestAccDurableTaskHubResource_requiresImport — Import detection
  • TestAccDurableTaskRetentionPolicyResource_basic — Create/destroy lifecycle
  • TestAccDurableTaskRetentionPolicyResource_complete — All retention policy properties
  • TestAccDurableTaskRetentionPolicyResource_update — In-place update
  • TestAccDurableTaskSchedulerDataSource_complete — Data source with full field validation

CI Results (commit 4e8c68f)

All CI checks passing ✅

test — PASS (4860 tests, 78 skipped in 193.753s)
DONE 4860 tests, 78 skipped in 193.753s

Go 1.25.9, ubuntu runner. Acceptance tests skipped (requires TF_ACC — runs in TeamCity).

golint — PASS (golangci-lint v2.4.0, 25 active linters, 0 issues)
Active linters: [asasalint asciicheck bidichk decorder dupword durationcheck errcheck gocritic
  gofmt gofumpt goimports govet ineffassign misspell nilerr prealloc predeclared reassign
  staticcheck tagalign unconvert unparam unused wastedassign whitespace]

Issues before processing: 304, after processing: 0
golangci-lint found no issues
Ran golangci-lint in 174164ms
gencheck — PASS (generated code matches committed code)
go generate ./internal/services/...
go generate ./internal/provider/
==> Comparing generated code to committed code...

No diff — generated code is in sync.

tflint — PASS (provider linting + terraform format check)
==> Checking source code against terraform provider linters...
==> Checking acceptance test terraform blocks are formatted...
depscheck — PASS (go mod vendor clean)
==> Checking source code with go mod vendor...

No diff — vendor directory is in sync.

website-lint — PASS (documentation validated)
==> Checking documentation for .html.markdown extension present
==> Checking documentation spelling...
==> Checking documentation for errors...
==> Checking documentation terraform blocks are formatted...
==> Validating documentation...
Found no errors
Other checks — all PASS
  • teamcity-test
  • secrets-check
  • detect
  • preview-api-version-linter

Change Log

This is a (please select all that apply):

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

Related Issue(s)

N/A — New service support for Azure Durable Task Framework.

AI Assistance Disclosure

  • AI Assisted - This contribution was made by, or with the assistance of, AI/LLMs

Rollback Plan

If a change needs to be reverted, we will publish an updated version of the provider.

Changes to Security Controls

No changes to security controls. This PR adds new resources for the Azure Durable Task service and does not modify existing access controls, encryption, or logging.

Note

If this PR changes meaningfully during the course of review please update the title and description as required.

stemaMSFT and others added 15 commits April 16, 2026 15:06
Core Implementation:
- Add durabletask service with typed resource implementation
- Implement Scheduler, TaskHub, and RetentionPolicy resources
- Add resource ID parsing and validation utilities
- Include implementation guide for next steps

Unit Tests:
- Add parse_test.go with resource ID parsing tests for all resource types
- Add validate_test.go with validation function tests
- Cover edge cases, error scenarios, and Azure-specific patterns
- Follow external test package convention (durabletask_test)
- Use testify assertions for clear test failures
- Test resource ID generation and case-insensitivity

Files Added:
- DURABLE_TASK_IMPLEMENTATION.md
- internal/services/durabletask/parse.go
- internal/services/durabletask/parse_test.go
- internal/services/durabletask/registration.go
- internal/services/durabletask/retention_policy_resource.go
- internal/services/durabletask/scheduler_resource.go
- internal/services/durabletask/task_hub_resource.go
- internal/services/durabletask/validate.go
- internal/services/durabletask/validate_test.go
The document-validate CI check was failing because the API Providers
section in the durable task scheduler data source documentation said
"This resource uses" instead of "This data source uses".

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@stemaMSFT stemaMSFT requested review from a team, WodansSon and magodo as code owners April 16, 2026 23:37
@stemaMSFT stemaMSFT changed the title Feature/durable task service v2 New Resource: azurerm_durable_task_scheduler, azurerm_durable_task_hub, `azurerm_durable_task_retention_policy Apr 16, 2026
stemaMSFT and others added 2 commits April 16, 2026 16:52
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…e, CustomizeDiff

- Fix schema field ordering: Required fields alphabetically before Optional
- Update method now uses delta/partial pattern with HasChange checks
- Remove sku_name from Update (ForceNew, never updated in-place)
- Add CustomizeDiff validating capacity only allowed with Dedicated SKU
- Add model struct comments separating Arguments from Attributes
- Add test case for Dedicated SKU with capacity

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@stemaMSFT stemaMSFT marked this pull request as draft April 17, 2026 00:16
stemaMSFT and others added 2 commits April 16, 2026 17:21
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Extract template() helpers in all resource test files
- Add complete data source test with Dedicated SKU
- Fix data source test variable naming (d -> r)
- Add computed field checks (id, ip_allow_list.#, tags.%)
- Create separate update() config to avoid ForceNew field changes
- Remove comments violating zero-tolerance policy

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@stemaMSFT stemaMSFT changed the title New Resource: azurerm_durable_task_scheduler, azurerm_durable_task_hub, `azurerm_durable_task_retention_policy New Resource: azurerm_durable_task_scheduler, azurerm_durable_task_hub, azurerm_durable_task_retention_policy & New Data Source: azurerm_durable_task_scheduler Apr 17, 2026
@stemaMSFT stemaMSFT marked this pull request as ready for review April 23, 2026 21:44
Copy link
Copy Markdown
Collaborator

@WodansSon WodansSon left a comment

Choose a reason for hiding this comment

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

Hey @stemaMSFT — thanks for this PR, I appreciate your work here!

I reviewed the PR and found some issues that need to be addressed.

Status: Changes Requested

Next steps

  1. Address/Reply to the PR comments.
  2. Run the usual checks locally, re-run the tests and attach the results again to the PR.
  3. When done, push the changes and reply here so I can re-check quickly — happy to re-review the updated code/docs.

Thanks again for the work here! 🚀

"retention_period_in_days": {
Type: pluginsdk.TypeInt,
Required: true,
ValidateFunc: validation.IntAtLeast(1),
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.

Can we have a better validation function here, what is the upper bound limit here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

added IntBetween(1, 90)

Comment on lines +29 to +33
return []sdk.Resource{
SchedulerResource{},
TaskHubResource{},
RetentionPolicyResource{},
}
Copy link
Copy Markdown
Collaborator

@WodansSon WodansSon Apr 24, 2026

Choose a reason for hiding this comment

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

Could we reorder the entries in the Resources() return slice so they are alphabetical as required by the contributing guidelines?

Suggested change
return []sdk.Resource{
SchedulerResource{},
TaskHubResource{},
RetentionPolicyResource{},
}
return []sdk.Resource{
RetentionPolicyResource{},
SchedulerResource{},
TaskHubResource{},
}

Reference: guide-breaking-changes

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Updated — the Resources() return slice is now alphabetically ordered: RetentionPolicyResource, SchedulerResource,
TaskHubResource.

Comment on lines +211 to +237
metadata.Logger.Infof("Updating retention policy on %s", schedulerId.ID())

policies := make([]retentionpolicies.RetentionPolicyDetails, 0)
for _, item := range model.RetentionPolicy {
policy := retentionpolicies.RetentionPolicyDetails{
RetentionPeriodInDays: item.RetentionPeriodInDays,
}

if item.OrchestrationState != "" {
state := retentionpolicies.PurgeableOrchestrationState(item.OrchestrationState)
policy.OrchestrationState = &state
}

policies = append(policies, policy)
}

properties := retentionpolicies.RetentionPolicyUpdate{
Properties: &retentionpolicies.RetentionPolicyProperties{
RetentionPolicies: &policies,
},
}

if err := client.UpdateThenPoll(ctx, schedulerId, properties); err != nil {
return fmt.Errorf("updating retention policy on %s: %+v", schedulerId.ID(), err)
}

return nil
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.

Can we add a change check for the updatable field(s) before performing the update? For example, short-circuit when the retention_policy hasn't changed to avoid unnecessary API calls:

Suggested change
metadata.Logger.Infof("Updating retention policy on %s", schedulerId.ID())
policies := make([]retentionpolicies.RetentionPolicyDetails, 0)
for _, item := range model.RetentionPolicy {
policy := retentionpolicies.RetentionPolicyDetails{
RetentionPeriodInDays: item.RetentionPeriodInDays,
}
if item.OrchestrationState != "" {
state := retentionpolicies.PurgeableOrchestrationState(item.OrchestrationState)
policy.OrchestrationState = &state
}
policies = append(policies, policy)
}
properties := retentionpolicies.RetentionPolicyUpdate{
Properties: &retentionpolicies.RetentionPolicyProperties{
RetentionPolicies: &policies,
},
}
if err := client.UpdateThenPoll(ctx, schedulerId, properties); err != nil {
return fmt.Errorf("updating retention policy on %s: %+v", schedulerId.ID(), err)
}
return nil
metadata.Logger.Infof("Updating retention policy on %s", schedulerId.ID())
if !metadata.ResourceData.HasChanges("retention_policy") {
metadata.Logger.Infof("No changes detected for retention_policy on %s", schedulerId.ID())
return nil
}
policies := make([]retentionpolicies.RetentionPolicyDetails, 0)
for _, item := range model.RetentionPolicy {
policy := retentionpolicies.RetentionPolicyDetails{
RetentionPeriodInDays: item.RetentionPeriodInDays,
}
if item.OrchestrationState != "" {
state := retentionpolicies.PurgeableOrchestrationState(item.OrchestrationState)
policy.OrchestrationState = &state
}
policies = append(policies, policy)
}
properties := retentionpolicies.RetentionPolicyUpdate{
Properties: &retentionpolicies.RetentionPolicyProperties{
RetentionPolicies: &policies,
},
}
if err := client.UpdateThenPoll(ctx, schedulerId, properties); err != nil {
return fmt.Errorf("updating retention policy on %s: %+v", schedulerId.ID(), err)
}
return nil

This follows the guidance in best-practices.md to ensure Update only performs work for changed fields (using d.HasChanges or the equivalent on the metadata object).

Reference: best-practices

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Added — the update function now short-circuits with metadata.ResourceData.HasChanges("retention_policy") to avoid unnecessary API calls when the retention policy hasn't changed.

Comment on lines +23 to +30
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).Key("id").Exists(),
check.That(data.ResourceName).Key("sku_name").HasValue("Consumption"),
check.That(data.ResourceName).Key("location").Exists(),
check.That(data.ResourceName).Key("endpoint").Exists(),
check.That(data.ResourceName).Key("ip_allow_list.#").Exists(),
check.That(data.ResourceName).Key("tags.%").HasValue("0"),
),
Copy link
Copy Markdown
Collaborator

@WodansSon WodansSon Apr 24, 2026

Choose a reason for hiding this comment

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

This depends on the answers to my earlier comments. I would avoid asserting redundancy_state here unless we first confirm that the field should remain exposed in the schema, is something the provider should surface to end users, and is reliably populated for the basic scheduler scenario. Likewise, I would only assert capacity here if we can confirm the API always returns it for the basic consumption configuration; otherwise the complete test seems like the better place to cover it.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Resolved — redundancy_state has been removed from both the resource and data source schemas entirely, so it's no longer asserted in tests.

Comment on lines +44 to +46
* `sku_name` - (Required) The SKU of the Durable Task Scheduler. Possible values include `Consumption` and `Dedicated`. Changing this forces a new resource to be created.

* `ip_allow_list` - (Required) A list of IP addresses or CIDR ranges that are allowed to access the Durable Task Scheduler.
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.

Required argument ordering, required arguments after location must be alphabetically sorted.

Suggested change
* `sku_name` - (Required) The SKU of the Durable Task Scheduler. Possible values include `Consumption` and `Dedicated`. Changing this forces a new resource to be created.
* `ip_allow_list` - (Required) A list of IP addresses or CIDR ranges that are allowed to access the Durable Task Scheduler.
* `ip_allow_list` - (Required) A list of IP addresses or CIDR ranges that are allowed to access the Durable Task Scheduler.
* `sku_name` - (Required) The SKU of the Durable Task Scheduler. Possible values include `Consumption` and `Dedicated`. Changing this forces a new resource to be created.

Reference: reference-documentation-standards

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Updated to the canonical phrasing: "Gets information about an existing Durable Task Scheduler."

Type: pluginsdk.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: ValidateSchedulerName,
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.

Can we move the validate code and tests into their own validate sub-folder/package to follow the providers resource validation pattern.

Suggested change
ValidateFunc: ValidateSchedulerName,
ValidateFunc: validate.SchedulerName,

Comment on lines +94 to +100
parsedId, err := schedulers.ParseSchedulerID(model.SchedulerId)
if err != nil {
return fmt.Errorf("parsing scheduler ID: %+v", err)
}

schedulerId := retentionpolicies.NewSchedulerID(parsedId.SubscriptionId, parsedId.ResourceGroupName, parsedId.SchedulerName)
id := NewRetentionPolicyID(parsedId.SubscriptionId, parsedId.ResourceGroupName, parsedId.SchedulerName)
Copy link
Copy Markdown
Collaborator

@WodansSon WodansSon Apr 24, 2026

Choose a reason for hiding this comment

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

Can you explain this to me? I do not understand yet why this resource needs a custom RetentionPolicyID / ParseRetentionPolicyID when the SDK already provides scheduler ID helpers. Is the intention that the Terraform state/import ID for this resource is the full singleton child path ending in /retentionPolicies/default, rather than the parent scheduler ID? If so, could you add a short comment explaining that design choice?

Type: pluginsdk.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: ValidateTaskHubName,
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.

Can we move the validate code and tests into their own validate sub-folder/package to follow the providers resource validation pattern.

Suggested change
ValidateFunc: ValidateTaskHubName,
ValidateFunc: validate.TaskHubName,

if !rawCapacity.IsNull() {
skuName := metadata.ResourceDiff.Get("sku_name").(string)
if skuName != string(schedulers.SchedulerSkuNameDedicated) {
return fmt.Errorf("`capacity` can only be configured when `sku_name` is set to `Dedicated`")
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.

This is a static error message and does not require the fmt.Errorf formatting functionality, can we update this?

Suggested change
return fmt.Errorf("`capacity` can only be configured when `sku_name` is set to `Dedicated`")
return errors.New("`capacity` can only be configured when `sku_name` is set to `Dedicated`")

// Copyright IBM Corp. 2014, 2025
// SPDX-License-Identifier: MPL-2.0

package durabletask_test
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 noticed that these tests do not have a negative test for the CustomizeDiff validation where it checks for capacity + sku_name = Consumption. The guard is implemented in the resource, but the current acceptance tests only cover the happy-path configurations and contains no ExpectError tests for this condition. Can we add that test case here?

Copy link
Copy Markdown
Collaborator

@WodansSon WodansSon left a comment

Choose a reason for hiding this comment

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

@stemaMSFT, I have another question about the RedundancyState field...

Tags map[string]string `tfschema:"tags"`

Endpoint string `tfschema:"endpoint"`
RedundancyState string `tfschema:"redundancy_state"`
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.

redundancy_state is a service-reported computed field, not a configurable argument. Do we want to expose this in the public schema at all? If it is not user-actionable or needed for parity with established provider patterns, I would prefer to remove it from both the resource and data source schemas.

- Move validate functions to validate/ subfolder

- Add consumptionWithCapacity test helper for CustomizeDiff validation

- Add parse_test.go for scheduler/task hub ID parsing

- Use SDK enum for SKU, errors.New, IntBetween(1,90)

- Add HasChanges guard, alphabetical registration

- Fix doc formatting across all 4 markdown files

- Remove redundancy_state from scheduler resource

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants