Skip to content

Commit

Permalink
fix(subscription): add time_sleep and azapi_resoure_action for su…
Browse files Browse the repository at this point in the history
…bscription association (#294)

* inital commit

* add required_provider time

* make docs && make fmt

* update unit tests

* update deploy tests
  • Loading branch information
luke-taylor authored Dec 7, 2023
1 parent 67c456b commit cc3e97f
Show file tree
Hide file tree
Showing 10 changed files with 122 additions and 15 deletions.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ The following requirements are needed by this module:

- <a name="requirement_azurerm"></a> [azurerm](#requirement\_azurerm) (>= 3.7.0)

- <a name="requirement_time"></a> [time](#requirement\_time) (>= 0.9.1)

## Modules

The following Modules are called:
Expand Down Expand Up @@ -912,6 +914,21 @@ map(object({

Default: `{}`

### <a name="input_wait_for_subscription_before_subscription_operations"></a> [wait\_for\_subscription\_before\_subscription\_operations](#input\_wait\_for\_subscription\_before\_subscription\_operations)

Description: The duration to wait after vending a subscription before performing subscription operations.

Type:

```hcl
object({
create = optional(string, "30s")
destroy = optional(string, "0s")
})
```

Default: `{}`

## Resources

The following resources are used by this module:
Expand Down
23 changes: 12 additions & 11 deletions main.subscription.tf
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ module "subscription" {
source = "./modules/subscription"
count = (var.subscription_id != "" && var.subscription_update_existing) || var.subscription_alias_enabled || var.subscription_management_group_association_enabled ? 1 : 0

subscription_alias_enabled = var.subscription_alias_enabled
subscription_alias_name = var.subscription_alias_name
subscription_billing_scope = var.subscription_billing_scope
subscription_display_name = var.subscription_display_name
subscription_id = var.subscription_id
subscription_management_group_association_enabled = var.subscription_management_group_association_enabled
subscription_management_group_id = var.subscription_management_group_id
subscription_tags = var.subscription_tags
subscription_use_azapi = var.subscription_use_azapi
subscription_update_existing = var.subscription_update_existing
subscription_workload = var.subscription_workload
subscription_alias_enabled = var.subscription_alias_enabled
subscription_alias_name = var.subscription_alias_name
subscription_billing_scope = var.subscription_billing_scope
subscription_display_name = var.subscription_display_name
subscription_id = var.subscription_id
subscription_management_group_association_enabled = var.subscription_management_group_association_enabled
subscription_management_group_id = var.subscription_management_group_id
subscription_tags = var.subscription_tags
subscription_use_azapi = var.subscription_use_azapi
subscription_update_existing = var.subscription_update_existing
subscription_workload = var.subscription_workload
wait_for_subscription_before_subscription_operations = var.wait_for_subscription_before_subscription_operations
}
19 changes: 19 additions & 0 deletions modules/subscription/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ The following requirements are needed by this module:

- <a name="requirement_azurerm"></a> [azurerm](#requirement\_azurerm) (>= 3.7.0)

- <a name="requirement_time"></a> [time](#requirement\_time) (>= 0.9.1)

## Modules

No modules.
Expand Down Expand Up @@ -202,15 +204,32 @@ Type: `string`

Default: `""`

### <a name="input_wait_for_subscription_before_subscription_operations"></a> [wait\_for\_subscription\_before\_subscription\_operations](#input\_wait\_for\_subscription\_before\_subscription\_operations)

Description: The duration to wait after vending a subscription before performing subscription operations.

Type:

```hcl
object({
create = optional(string, "30s")
destroy = optional(string, "0s")
})
```

Default: `{}`

## Resources

The following resources are used by this module:

- [azapi_resource.subscription](https://registry.terraform.io/providers/Azure/azapi/latest/docs/resources/resource) (resource)
- [azapi_resource_action.subscription_association](https://registry.terraform.io/providers/Azure/azapi/latest/docs/resources/resource_action) (resource)
- [azapi_resource_action.subscription_rename](https://registry.terraform.io/providers/Azure/azapi/latest/docs/resources/resource_action) (resource)
- [azapi_update_resource.subscription_tags](https://registry.terraform.io/providers/Azure/azapi/latest/docs/resources/update_resource) (resource)
- [azurerm_management_group_subscription_association.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/management_group_subscription_association) (resource)
- [azurerm_subscription.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subscription) (resource)
- [time_sleep.wait_for_subscription_before_subscription_operations](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) (resource)

## Outputs

Expand Down
37 changes: 35 additions & 2 deletions modules/subscription/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ resource "azurerm_subscription" "this" {
# This resource ensures that we can manage the management group for the subscription
# throughout its lifecycle.
resource "azurerm_management_group_subscription_association" "this" {
count = var.subscription_management_group_association_enabled ? 1 : 0
count = var.subscription_management_group_association_enabled && !var.subscription_use_azapi ? 1 : 0
management_group_id = "/providers/Microsoft.Management/managementGroups/${var.subscription_management_group_id}"
subscription_id = "/subscriptions/${local.subscription_id}"
}
Expand All @@ -37,11 +37,35 @@ resource "azapi_resource" "subscription" {
response_export_values = ["properties.subscriptionId"]
lifecycle {
ignore_changes = [
body
body,
name
]
}
}

resource "time_sleep" "wait_for_subscription_before_subscription_operations" {
count = var.subscription_alias_enabled && var.subscription_use_azapi ? 1 : 0

create_duration = var.wait_for_subscription_before_subscription_operations.create
destroy_duration = var.wait_for_subscription_before_subscription_operations.destroy

depends_on = [
azapi_resource.subscription
]
}

resource "azapi_resource_action" "subscription_association" {
count = var.subscription_management_group_association_enabled && var.subscription_use_azapi ? 1 : 0

type = "Microsoft.Management/managementGroups/subscriptions@2021-04-01"
resource_id = "/providers/Microsoft.Management/managementGroups/${var.subscription_management_group_id}/subscriptions/${jsondecode(azapi_resource.subscription[0].output).properties.subscriptionId}"
method = "PUT"

depends_on = [
time_sleep.wait_for_subscription_before_subscription_operations
]
}

resource "azapi_update_resource" "subscription_tags" {
count = (var.subscription_alias_enabled && var.subscription_use_azapi) || (var.subscription_id != "" && var.subscription_update_existing) ? 1 : 0

Expand All @@ -52,6 +76,10 @@ resource "azapi_update_resource" "subscription_tags" {
tags = var.subscription_tags
}
})

depends_on = [
time_sleep.wait_for_subscription_before_subscription_operations
]
}

resource "azapi_resource_action" "subscription_rename" {
Expand All @@ -64,4 +92,9 @@ resource "azapi_resource_action" "subscription_rename" {
body = jsonencode({
subscriptionName = var.subscription_display_name
})

depends_on = [
time_sleep.wait_for_subscription_before_subscription_operations
]
}

4 changes: 4 additions & 0 deletions modules/subscription/terraform.tf
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,9 @@ terraform {
source = "Azure/azapi"
version = ">= 1.3.0"
}
time = {
source = "hashicorp/time"
version = ">= 0.9.1"
}
}
}
11 changes: 11 additions & 0 deletions modules/subscription/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,14 @@ If enabled, the following must also be supplied:
- `subscription_id`
DESCRIPTION
}

variable "wait_for_subscription_before_subscription_operations" {
type = object({
create = optional(string, "30s")
destroy = optional(string, "0s")
})
default = {}
description = <<DESCRIPTION
The duration to wait after vending a subscription before performing subscription operations.
DESCRIPTION
}
4 changes: 4 additions & 0 deletions terraform.tf
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,9 @@ terraform {
source = "azure/azapi"
version = ">= 1.4.0"
}
time = {
source = "hashicorp/time"
version = ">= 0.9.1"
}
}
}
7 changes: 6 additions & 1 deletion tests/subscription/subscriptionDeploy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
)

var billingScope = os.Getenv("AZURE_BILLING_SCOPE")
var tenantId = os.Getenv("AZURE_TENANT_ID")

// TestDeploySubscriptionAliasValid tests the deployment of a subscription alias
// with valid input variables.
Expand Down Expand Up @@ -71,7 +72,7 @@ func TestDeploySubscriptionAliasValidAzApi(t *testing.T) {
require.NoError(t, err)
defer test.Cleanup()

check.InPlan(test.PlanStruct).NumberOfResourcesEquals(3).ErrorIsNil(t)
check.InPlan(test.PlanStruct).NumberOfResourcesEquals(4).ErrorIsNil(t)

// Defer the cleanup of the subscription alias to the end of the test.
// Should be run after the Terraform destroy.
Expand Down Expand Up @@ -185,6 +186,10 @@ func TestDeploySubscriptionAliasManagementGroupValidAzApi(t *testing.T) {

err = azureutils.IsSubscriptionInManagementGroup(t, u, v["subscription_management_group_id"].(string))
assert.NoErrorf(t, err, "subscription %s is not in management group %s", sid, v["subscription_management_group_id"].(string))

if err := azureutils.SetSubscriptionManagementGroup(u, tenantId); err != nil {
t.Logf("cannot move subscription to tenant root group: %v", err)
}
}

// getValidInputVariables returns a set of valid input variables that can be used and modified for testing scenarios.
Expand Down
4 changes: 3 additions & 1 deletion tests/subscription/subscription_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func TestSubscriptionAliasCreateValidAzApi(t *testing.T) {
"azapi_resource.subscription[0]",
"azapi_resource_action.subscription_rename[0]",
"azapi_update_resource.subscription_tags[0]",
"time_sleep.wait_for_subscription_before_subscription_operations[0]",
}

check.InPlan(test.PlanStruct).NumberOfResourcesEquals(len(resources)).ErrorIsNil(t)
Expand Down Expand Up @@ -105,7 +106,8 @@ func TestSubscriptionAliasCreateValidWithManagementGroupAzApi(t *testing.T) {
"azapi_resource.subscription[0]",
"azapi_resource_action.subscription_rename[0]",
"azapi_update_resource.subscription_tags[0]",
"azurerm_management_group_subscription_association.this[0]",
"azapi_resource_action.subscription_association[0]",
"time_sleep.wait_for_subscription_before_subscription_operations[0]",
}

check.InPlan(test.PlanStruct).NumberOfResourcesEquals(len(resources)).ErrorIsNil(t)
Expand Down
11 changes: 11 additions & 0 deletions variables.subscription.tf
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,14 @@ If enabled, the following must also be supplied:
- `subscription_id`
DESCRIPTION
}

variable "wait_for_subscription_before_subscription_operations" {
type = object({
create = optional(string, "30s")
destroy = optional(string, "0s")
})
default = {}
description = <<DESCRIPTION
The duration to wait after vending a subscription before performing subscription operations.
DESCRIPTION
}

0 comments on commit cc3e97f

Please sign in to comment.