Skip to content

Commit

Permalink
Merge pull request #14524 from datarootsio/template-data-sources
Browse files Browse the repository at this point in the history
New data sources `azurerm_management_group_template_deployment`, `azurerm_resource_group_template_deployment`, `azurerm_subscription_template_deployment`, `azurerm_tenant_template_deployment`
  • Loading branch information
tombuildsstuff authored Jun 22, 2022
2 parents 753b88a + 5e80c50 commit 48a5ebf
Show file tree
Hide file tree
Showing 14 changed files with 773 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package resource

import (
"fmt"
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-provider-azurerm/internal/clients"
mgValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/managementgroup/validate"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/resource/validate"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/timeouts"
"github.com/hashicorp/terraform-provider-azurerm/utils"
)

func dataSourceManagementGroupTemplateDeployment() *pluginsdk.Resource {
return &pluginsdk.Resource{
Read: dataSourceManagementGroupTemplateDeploymentRead,

Timeouts: &pluginsdk.ResourceTimeout{
Read: pluginsdk.DefaultTimeout(5 * time.Minute),
},

Schema: map[string]*pluginsdk.Schema{
"name": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: validate.TemplateDeploymentName,
},

"management_group_id": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: mgValidate.ManagementGroupID,
},

// Computed
"output_content": {
Type: pluginsdk.TypeString,
Computed: true,
// NOTE: outputs can be strings, ints, objects etc - whilst using a nested object was considered
// parsing the JSON using `jsondecode` allows the users to interact with/map objects as required
},
},
}
}

func dataSourceManagementGroupTemplateDeploymentRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Resource.DeploymentsClient
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()

managementGroupId := d.Get("management_group_id").(string)
deploymentName := d.Get("name").(string)

resp, err := client.GetAtManagementGroupScope(ctx, managementGroupId, deploymentName)
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
return fmt.Errorf("deployment %s in Management Group %s was not found", deploymentName, managementGroupId)
}

return fmt.Errorf("retrieving Management Group Template Deployment %s in management group %s: %+v", deploymentName, managementGroupId, err)
}

d.SetId(*resp.ID)

if props := resp.Properties; props != nil {
flattenedOutputs, err := flattenTemplateDeploymentBody(props.Outputs)
if err != nil {
return fmt.Errorf("flattening `output_content`: %+v", err)
}
return d.Set("output_content", flattenedOutputs)
}

return nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package resource_test

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance"
"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check"
)

type ManagementGroupTemplateDeploymentDataSource struct{}

func TestAccDataSourceManagementGroupTemplateDeployment(t *testing.T) {
data := acceptance.BuildTestData(t, "data.azurerm_management_group_template_deployment", "test")
r := ManagementGroupTemplateDeploymentDataSource{}

data.DataSourceTest(t, []acceptance.TestStep{
{
Config: r.withOutputsConfig(data),
},
{
Config: r.withDataSource(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).Key("output_content").HasValue("{\"testOutput\":{\"type\":\"String\",\"value\":\"some-value\"}}"),
),
},
})
}

func (ManagementGroupTemplateDeploymentDataSource) withOutputsConfig(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}
resource "azurerm_management_group" "test" {
name = "TestAcc-Deployment-%[1]d"
}
resource "azurerm_management_group_template_deployment" "test" {
name = "acctestMGdeploy-%[1]d"
management_group_id = azurerm_management_group.test.id
location = %[2]q
template_content = <<TEMPLATE
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"variables": {},
"resources": [],
"outputs": {
"testOutput": {
"type": "String",
"value": "some-value"
}
}
}
TEMPLATE
}
`, data.RandomInteger, data.Locations.Primary)
}

func (r ManagementGroupTemplateDeploymentDataSource) withDataSource(data acceptance.TestData) string {
return fmt.Sprintf(`
%s
data "azurerm_management_group_template_deployment" "test" {
name = azurerm_management_group_template_deployment.test.name
management_group_id = azurerm_management_group.test.id
}
`, r.withOutputsConfig(data))
}
10 changes: 7 additions & 3 deletions internal/services/resource/registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,13 @@ func (r Registration) WebsiteCategories() []string {
// SupportedDataSources returns the supported Data Sources supported by this Service
func (r Registration) SupportedDataSources() map[string]*pluginsdk.Resource {
return map[string]*pluginsdk.Resource{
"azurerm_resources": dataSourceResources(),
"azurerm_resource_group": dataSourceResourceGroup(),
"azurerm_template_spec_version": dataSourceTemplateSpecVersion(),
"azurerm_resources": dataSourceResources(),
"azurerm_resource_group": dataSourceResourceGroup(),
"azurerm_template_spec_version": dataSourceTemplateSpecVersion(),
"azurerm_management_group_template_deployment": dataSourceManagementGroupTemplateDeployment(),
"azurerm_resource_group_template_deployment": dataSourceResourceGroupTemplateDeployment(),
"azurerm_subscription_template_deployment": dataSourceSubscriptionTemplateDeployment(),
"azurerm_tenant_template_deployment": dataSourceTenantTemplateDeployment(),
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package resource

import (
"fmt"
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-provider-azurerm/helpers/azure"
"github.com/hashicorp/terraform-provider-azurerm/internal/clients"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/resource/parse"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/resource/validate"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/timeouts"
"github.com/hashicorp/terraform-provider-azurerm/utils"
)

func dataSourceResourceGroupTemplateDeployment() *pluginsdk.Resource {
return &pluginsdk.Resource{
Read: dataSourceResourceGroupTemplateDeploymentRead,

Timeouts: &pluginsdk.ResourceTimeout{
Read: pluginsdk.DefaultTimeout(5 * time.Minute),
},

Schema: map[string]*pluginsdk.Schema{
"name": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: validate.TemplateDeploymentName,
},

"resource_group_name": azure.SchemaResourceGroupNameForDataSource(),

// Computed
"output_content": {
Type: pluginsdk.TypeString,
Computed: true,
// NOTE: outputs can be strings, ints, objects etc - whilst using a nested object was considered
// parsing the JSON using `jsondecode` allows the users to interact with/map objects as required
},
},
}
}

func dataSourceResourceGroupTemplateDeploymentRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Resource.DeploymentsClient
subscriptionId := meta.(*clients.Client).Account.SubscriptionId
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()

resourceGroupName := d.Get("resource_group_name").(string)
deploymentName := d.Get("name").(string)
id := parse.NewResourceGroupTemplateDeploymentID(subscriptionId, resourceGroupName, deploymentName)

resp, err := client.Get(ctx, id.ResourceGroup, id.DeploymentName)
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
return fmt.Errorf("template %s in resource Group %s was not found", deploymentName, resourceGroupName)
}

return fmt.Errorf("retrieving Template Deployment %q (Resource Group %q): %+v", id.DeploymentName, id.ResourceGroup, err)
}

d.SetId(id.ID())

if props := resp.Properties; props != nil {
flattenedOutputs, err := flattenTemplateDeploymentBody(props.Outputs)
if err != nil {
return fmt.Errorf("flattening `output_content`: %+v", err)
}
return d.Set("output_content", flattenedOutputs)
}

return nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package resource_test

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance"
"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check"
)

type ResourceGroupTemplateDeploymentDataSource struct{}

func TestAccDataSourceResourceGroupTemplateDeployment(t *testing.T) {
data := acceptance.BuildTestData(t, "data.azurerm_resource_group_template_deployment", "test")
r := ResourceGroupTemplateDeploymentDataSource{}

data.DataSourceTest(t, []acceptance.TestStep{
{
Config: r.withOutputsConfig(data),
},
{
Config: r.withDataSource(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).Key("output_content").HasValue("{\"testOutput\":{\"type\":\"String\",\"value\":\"some-value\"}}"),
),
},
})
}

func (ResourceGroupTemplateDeploymentDataSource) withOutputsConfig(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "test" {
name = "acctestRG-%d"
location = %q
}
resource "azurerm_resource_group_template_deployment" "test" {
name = "acctest"
resource_group_name = azurerm_resource_group.test.name
deployment_mode = "Complete"
template_content = <<TEMPLATE
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"variables": {},
"resources": [],
"outputs": {
"testOutput": {
"type": "String",
"value": "some-value"
}
}
}
TEMPLATE
}
`, data.RandomInteger, data.Locations.Primary)
}

func (r ResourceGroupTemplateDeploymentDataSource) withDataSource(data acceptance.TestData) string {
return fmt.Sprintf(`
%s
data "azurerm_resource_group_template_deployment" "test" {
name = azurerm_resource_group_template_deployment.test.name
resource_group_name = azurerm_resource_group.test.name
}
`, r.withOutputsConfig(data))
}
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ resource "azurerm_resource_group_template_deployment" "test" {
resource_group_name = azurerm_resource_group.test.name
deployment_mode = %q
tags = {
Hello = "World"
hello = "world"
}
template_content = <<TEMPLATE
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package resource

import (
"fmt"
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-provider-azurerm/internal/clients"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/resource/parse"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/resource/validate"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/timeouts"
"github.com/hashicorp/terraform-provider-azurerm/utils"
)

func dataSourceSubscriptionTemplateDeployment() *pluginsdk.Resource {
return &pluginsdk.Resource{
Read: dataSourceSubscriptionTemplateDeploymentRead,
Timeouts: &pluginsdk.ResourceTimeout{
Read: pluginsdk.DefaultTimeout(5 * time.Minute),
},
Schema: map[string]*pluginsdk.Schema{
"name": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: validate.TemplateDeploymentName,
},

// Computed
"output_content": {
Type: pluginsdk.TypeString,
Computed: true,
// NOTE: outputs can be strings, ints, objects etc - whilst using a nested object was considered
// parsing the JSON using `jsondecode` allows the users to interact with/map objects as required
},
},
}
}

func dataSourceSubscriptionTemplateDeploymentRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Resource.DeploymentsClient
subscriptionId := meta.(*clients.Client).Account.SubscriptionId
ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d)
defer cancel()

id := parse.NewSubscriptionTemplateDeploymentID(subscriptionId, d.Get("name").(string))

resp, err := client.GetAtSubscriptionScope(ctx, id.DeploymentName)
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
return fmt.Errorf("template %s in subscription %s was not found", id.DeploymentName, subscriptionId)
}

return fmt.Errorf("retrieving Subscription Template Deployment %q: %+v", id.DeploymentName, err)
}

d.SetId(id.ID())

if props := resp.Properties; props != nil {
flattenedOutputs, err := flattenTemplateDeploymentBody(props.Outputs)
if err != nil {
return fmt.Errorf("flattening `output_content`: %+v", err)
}
return d.Set("output_content", flattenedOutputs)
}

return nil
}
Loading

0 comments on commit 48a5ebf

Please sign in to comment.