From 0691c0eb91e1dcfa4f6b9bbdb7756ec370d9f940 Mon Sep 17 00:00:00 2001 From: James Nugent Date: Wed, 1 Jun 2016 19:32:25 -0500 Subject: [PATCH] provider/azurerm: Fix azurerm_template_deployment Tests are too slow to run. --- builtin/providers/azurerm/provider.go | 2 +- .../resource_arm_template_deployment.go | 431 +++++++-------- .../resource_arm_template_deployment_test.go | 498 +++++++++--------- 3 files changed, 470 insertions(+), 461 deletions(-) diff --git a/builtin/providers/azurerm/provider.go b/builtin/providers/azurerm/provider.go index 57ea897d43..3f15d07ab5 100644 --- a/builtin/providers/azurerm/provider.go +++ b/builtin/providers/azurerm/provider.go @@ -60,7 +60,7 @@ func Provider() terraform.ResourceProvider { "azurerm_storage_container": resourceArmStorageContainer(), "azurerm_storage_queue": resourceArmStorageQueue(), "azurerm_subnet": resourceArmSubnet(), - //"azurerm_template_deployment": resourceArmTemplateDeployment(), + "azurerm_template_deployment": resourceArmTemplateDeployment(), //"azurerm_virtual_machine": resourceArmVirtualMachine(), "azurerm_virtual_network": resourceArmVirtualNetwork(), diff --git a/builtin/providers/azurerm/resource_arm_template_deployment.go b/builtin/providers/azurerm/resource_arm_template_deployment.go index d7dabf34ba..79f400715d 100644 --- a/builtin/providers/azurerm/resource_arm_template_deployment.go +++ b/builtin/providers/azurerm/resource_arm_template_deployment.go @@ -1,213 +1,222 @@ package azurerm -//import ( -// "encoding/json" -// "fmt" -// "log" -// "net/http" -// "strings" -// "time" -// -// "github.com/Azure/azure-sdk-for-go/arm/resources/resources" -// "github.com/hashicorp/terraform/helper/resource" -// "github.com/hashicorp/terraform/helper/schema" -//) -// -//func resourceArmTemplateDeployment() *schema.Resource { -// return &schema.Resource{ -// Create: resourceArmTemplateDeploymentCreate, -// Read: resourceArmTemplateDeploymentRead, -// Update: resourceArmTemplateDeploymentCreate, -// Delete: resourceArmTemplateDeploymentDelete, -// -// Schema: map[string]*schema.Schema{ -// "name": &schema.Schema{ -// Type: schema.TypeString, -// Required: true, -// ForceNew: true, -// }, -// -// "resource_group_name": &schema.Schema{ -// Type: schema.TypeString, -// Required: true, -// ForceNew: true, -// }, -// -// "template_body": &schema.Schema{ -// Type: schema.TypeString, -// Optional: true, -// Computed: true, -// StateFunc: normalizeJson, -// }, -// -// "parameters": &schema.Schema{ -// Type: schema.TypeMap, -// Optional: true, -// }, -// -// "outputs": &schema.Schema{ -// Type: schema.TypeMap, -// Computed: true, -// }, -// -// "deployment_mode": &schema.Schema{ -// Type: schema.TypeString, -// Required: true, -// }, -// }, -// } -//} -// -//func resourceArmTemplateDeploymentCreate(d *schema.ResourceData, meta interface{}) error { -// client := meta.(*ArmClient) -// deployClient := client.deploymentsClient -// -// name := d.Get("name").(string) -// resGroup := d.Get("resource_group_name").(string) -// deploymentMode := d.Get("deployment_mode").(string) -// -// log.Printf("[INFO] preparing arguments for Azure ARM Template Deployment creation.") -// properties := resources.DeploymentProperties{ -// Mode: resources.DeploymentMode(deploymentMode), -// } -// -// if v, ok := d.GetOk("parameters"); ok { -// params := v.(map[string]interface{}) -// -// newParams := make(map[string]interface{}, len(params)) -// for key, val := range params { -// newParams[key] = struct { -// Value interface{} -// }{ -// Value: val, -// } -// } -// -// properties.Parameters = &newParams -// } -// -// if v, ok := d.GetOk("template_body"); ok { -// template, err := expandTemplateBody(v.(string)) -// if err != nil { -// return err -// } -// -// properties.Template = &template -// } -// -// deployment := resources.Deployment{ -// Properties: &properties, -// } -// resp, err := deployClient.CreateOrUpdate(resGroup, name, deployment) -// if err != nil { -// return nil -// } -// -// d.SetId(*resp.ID) -// -// log.Printf("[DEBUG] Waiting for Template Deployment (%s) to become available", name) -// stateConf := &resource.StateChangeConf{ -// Pending: []string{"creating", "updating", "accepted", "running"}, -// Target: []string{"succeeded"}, -// Refresh: templateDeploymentStateRefreshFunc(client, resGroup, name), -// Timeout: 40 * time.Minute, -// } -// if _, err := stateConf.WaitForState(); err != nil { -// return fmt.Errorf("Error waiting for Template Deployment (%s) to become available: %s", name, err) -// } -// -// return resourceArmTemplateDeploymentRead(d, meta) -//} -// -//func resourceArmTemplateDeploymentRead(d *schema.ResourceData, meta interface{}) error { -// client := meta.(*ArmClient) -// deployClient := client.deploymentsClient -// -// id, err := parseAzureResourceID(d.Id()) -// if err != nil { -// return err -// } -// resGroup := id.ResourceGroup -// name := id.Path["deployments"] -// if name == "" { -// name = id.Path["Deployments"] -// } -// -// resp, err := deployClient.Get(resGroup, name) -// if resp.StatusCode == http.StatusNotFound { -// d.SetId("") -// return nil -// } -// if err != nil { -// return fmt.Errorf("Error making Read request on Azure RM Template Deployment %s: %s", name, err) -// } -// var outputs map[string]string -// if resp.Properties.Outputs != nil && len(*resp.Properties.Outputs) > 0 { -// outputs = make(map[string]string) -// for key, output := range *resp.Properties.Outputs { -// outputMap := output.(map[string]interface{}) -// outputValue, ok := outputMap["value"] -// if !ok { -// // No value -// continue -// } -// -// outputs[key] = outputValue.(string) -// } -// } -// -// d.Set("outputs", outputs) -// -// return nil -//} -// -//func resourceArmTemplateDeploymentDelete(d *schema.ResourceData, meta interface{}) error { -// client := meta.(*ArmClient) -// deployClient := client.deploymentsClient -// -// id, err := parseAzureResourceID(d.Id()) -// if err != nil { -// return err -// } -// resGroup := id.ResourceGroup -// name := id.Path["deployments"] -// if name == "" { -// name = id.Path["Deployments"] -// } -// -// _, err = deployClient.Delete(resGroup, name) -// return nil -//} -// -//func expandTemplateBody(template string) (map[string]interface{}, error) { -// var templateBody map[string]interface{} -// err := json.Unmarshal([]byte(template), &templateBody) -// if err != nil { -// return nil, fmt.Errorf("Error Expanding the template_body for Azure RM Template Deployment") -// } -// return templateBody, nil -//} -// -//func normalizeJson(jsonString interface{}) string { -// if jsonString == nil || jsonString == "" { -// return "" -// } -// var j interface{} -// err := json.Unmarshal([]byte(jsonString.(string)), &j) -// if err != nil { -// return fmt.Sprintf("Error parsing JSON: %s", err) -// } -// b, _ := json.Marshal(j) -// return string(b[:]) -//} -// -//func templateDeploymentStateRefreshFunc(client *ArmClient, resourceGroupName string, name string) resource.StateRefreshFunc { -// return func() (interface{}, string, error) { -// res, err := client.deploymentsClient.Get(resourceGroupName, name) -// if err != nil { -// return nil, "", fmt.Errorf("Error issuing read request in templateDeploymentStateRefreshFunc to Azure ARM for Template Deployment '%s' (RG: '%s'): %s", name, resourceGroupName, err) -// } -// -// return res, strings.ToLower(*res.Properties.ProvisioningState), nil -// } -//} +import ( + "encoding/json" + "fmt" + "log" + "net/http" + "strings" + "time" + + "github.com/Azure/azure-sdk-for-go/arm/resources/resources" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceArmTemplateDeployment() *schema.Resource { + return &schema.Resource{ + Create: resourceArmTemplateDeploymentCreate, + Read: resourceArmTemplateDeploymentRead, + Update: resourceArmTemplateDeploymentCreate, + Delete: resourceArmTemplateDeploymentDelete, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "resource_group_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "template_body": { + Type: schema.TypeString, + Optional: true, + Computed: true, + StateFunc: normalizeJson, + }, + + "parameters": { + Type: schema.TypeMap, + Optional: true, + }, + + "outputs": { + Type: schema.TypeMap, + Computed: true, + }, + + "deployment_mode": { + Type: schema.TypeString, + Required: true, + }, + }, + } +} + +func resourceArmTemplateDeploymentCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient) + deployClient := client.deploymentsClient + + name := d.Get("name").(string) + resGroup := d.Get("resource_group_name").(string) + deploymentMode := d.Get("deployment_mode").(string) + + log.Printf("[INFO] preparing arguments for Azure ARM Template Deployment creation.") + properties := resources.DeploymentProperties{ + Mode: resources.DeploymentMode(deploymentMode), + } + + if v, ok := d.GetOk("parameters"); ok { + params := v.(map[string]interface{}) + + newParams := make(map[string]interface{}, len(params)) + for key, val := range params { + newParams[key] = struct { + Value interface{} + }{ + Value: val, + } + } + + properties.Parameters = &newParams + } + + if v, ok := d.GetOk("template_body"); ok { + template, err := expandTemplateBody(v.(string)) + if err != nil { + return err + } + + properties.Template = &template + } + + deployment := resources.Deployment{ + Properties: &properties, + } + + _, err := deployClient.CreateOrUpdate(resGroup, name, deployment, make(chan struct{})) + if err != nil { + return nil + } + + read, err := deployClient.Get(resGroup, name) + if err != nil { + return err + } + if read.ID == nil { + return fmt.Errorf("Cannot read Template Deployment %s (resource group %s) ID", name, resGroup) + } + + d.SetId(*read.ID) + + log.Printf("[DEBUG] Waiting for Template Deployment (%s) to become available", name) + stateConf := &resource.StateChangeConf{ + Pending: []string{"creating", "updating", "accepted", "running"}, + Target: []string{"succeeded"}, + Refresh: templateDeploymentStateRefreshFunc(client, resGroup, name), + Timeout: 40 * time.Minute, + } + if _, err := stateConf.WaitForState(); err != nil { + return fmt.Errorf("Error waiting for Template Deployment (%s) to become available: %s", name, err) + } + + return resourceArmTemplateDeploymentRead(d, meta) +} + +func resourceArmTemplateDeploymentRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient) + deployClient := client.deploymentsClient + + id, err := parseAzureResourceID(d.Id()) + if err != nil { + return err + } + resGroup := id.ResourceGroup + name := id.Path["deployments"] + if name == "" { + name = id.Path["Deployments"] + } + + resp, err := deployClient.Get(resGroup, name) + if resp.StatusCode == http.StatusNotFound { + d.SetId("") + return nil + } + if err != nil { + return fmt.Errorf("Error making Read request on Azure RM Template Deployment %s: %s", name, err) + } + var outputs map[string]string + if resp.Properties.Outputs != nil && len(*resp.Properties.Outputs) > 0 { + outputs = make(map[string]string) + for key, output := range *resp.Properties.Outputs { + outputMap := output.(map[string]interface{}) + outputValue, ok := outputMap["value"] + if !ok { + // No value + continue + } + + outputs[key] = outputValue.(string) + } + } + + d.Set("outputs", outputs) + + return nil +} + +func resourceArmTemplateDeploymentDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient) + deployClient := client.deploymentsClient + + id, err := parseAzureResourceID(d.Id()) + if err != nil { + return err + } + resGroup := id.ResourceGroup + name := id.Path["deployments"] + if name == "" { + name = id.Path["Deployments"] + } + + _, err = deployClient.Delete(resGroup, name, make(chan struct{})) + return nil +} + +func expandTemplateBody(template string) (map[string]interface{}, error) { + var templateBody map[string]interface{} + err := json.Unmarshal([]byte(template), &templateBody) + if err != nil { + return nil, fmt.Errorf("Error Expanding the template_body for Azure RM Template Deployment") + } + return templateBody, nil +} + +func normalizeJson(jsonString interface{}) string { + if jsonString == nil || jsonString == "" { + return "" + } + var j interface{} + err := json.Unmarshal([]byte(jsonString.(string)), &j) + if err != nil { + return fmt.Sprintf("Error parsing JSON: %s", err) + } + b, _ := json.Marshal(j) + return string(b[:]) +} + +func templateDeploymentStateRefreshFunc(client *ArmClient, resourceGroupName string, name string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + res, err := client.deploymentsClient.Get(resourceGroupName, name) + if err != nil { + return nil, "", fmt.Errorf("Error issuing read request in templateDeploymentStateRefreshFunc to Azure ARM for Template Deployment '%s' (RG: '%s'): %s", name, resourceGroupName, err) + } + + return res, strings.ToLower(*res.Properties.ProvisioningState), nil + } +} diff --git a/builtin/providers/azurerm/resource_arm_template_deployment_test.go b/builtin/providers/azurerm/resource_arm_template_deployment_test.go index 0a3707d645..be23e9d60d 100644 --- a/builtin/providers/azurerm/resource_arm_template_deployment_test.go +++ b/builtin/providers/azurerm/resource_arm_template_deployment_test.go @@ -1,251 +1,251 @@ package azurerm -//import ( -// "fmt" -// "net/http" -// "testing" -// -// "github.com/hashicorp/terraform/helper/acctest" -// "github.com/hashicorp/terraform/helper/resource" -// "github.com/hashicorp/terraform/terraform" -//) -// -//func TestAccAzureRMTemplateDeployment_basic(t *testing.T) { -// ri := acctest.RandInt() -// config := fmt.Sprintf(testAccAzureRMTemplateDeployment_basicExample, ri, ri) -// resource.Test(t, resource.TestCase{ -// PreCheck: func() { testAccPreCheck(t) }, -// Providers: testAccProviders, -// CheckDestroy: testCheckAzureRMTemplateDeploymentDestroy, -// Steps: []resource.TestStep{ -// resource.TestStep{ -// Config: config, -// Check: resource.ComposeTestCheckFunc( -// testCheckAzureRMTemplateDeploymentExists("azurerm_template_deployment.test"), -// ), -// }, -// }, -// }) -//} -// -//func TestAccAzureRMTemplateDeployment_withParams(t *testing.T) { -// ri := acctest.RandInt() -// config := fmt.Sprintf(testAccAzureRMTemplateDeployment_withParams, ri, ri, ri) -// resource.Test(t, resource.TestCase{ -// PreCheck: func() { testAccPreCheck(t) }, -// Providers: testAccProviders, -// CheckDestroy: testCheckAzureRMTemplateDeploymentDestroy, -// Steps: []resource.TestStep{ -// resource.TestStep{ -// Config: config, -// Check: resource.ComposeTestCheckFunc( -// testCheckAzureRMTemplateDeploymentExists("azurerm_template_deployment.test"), -// resource.TestCheckResourceAttr("azurerm_template_deployment.test", "outputs.testOutput", "Output Value"), -// ), -// }, -// }, -// }) -//} -// -//func testCheckAzureRMTemplateDeploymentExists(name string) resource.TestCheckFunc { -// return func(s *terraform.State) error { -// // Ensure we have enough information in state to look up in API -// rs, ok := s.RootModule().Resources[name] -// if !ok { -// return fmt.Errorf("Not found: %s", name) -// } -// -// name := rs.Primary.Attributes["name"] -// resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] -// if !hasResourceGroup { -// return fmt.Errorf("Bad: no resource group found in state for template deployment: %s", name) -// } -// -// conn := testAccProvider.Meta().(*ArmClient).deploymentsClient -// -// resp, err := conn.Get(resourceGroup, name) -// if err != nil { -// return fmt.Errorf("Bad: Get on deploymentsClient: %s", err) -// } -// -// if resp.StatusCode == http.StatusNotFound { -// return fmt.Errorf("Bad: TemplateDeployment %q (resource group: %q) does not exist", name, resourceGroup) -// } -// -// return nil -// } -//} -// -//func testCheckAzureRMTemplateDeploymentDestroy(s *terraform.State) error { -// conn := testAccProvider.Meta().(*ArmClient).vmClient -// -// for _, rs := range s.RootModule().Resources { -// if rs.Type != "azurerm_template_deployment" { -// continue -// } -// -// name := rs.Primary.Attributes["name"] -// resourceGroup := rs.Primary.Attributes["resource_group_name"] -// -// resp, err := conn.Get(resourceGroup, name, "") -// -// if err != nil { -// return nil -// } -// -// if resp.StatusCode != http.StatusNotFound { -// return fmt.Errorf("Template Deployment still exists:\n%#v", resp.Properties) -// } -// } -// -// return nil -//} -// -//var testAccAzureRMTemplateDeployment_basicExample = ` -// resource "azurerm_resource_group" "test" { -// name = "acctestrg-%d" -// location = "West US" -// } -// -// resource "azurerm_template_deployment" "test" { -// name = "acctesttemplate-%d" -// resource_group_name = "${azurerm_resource_group.test.name}" -// template_body = <