-
Notifications
You must be signed in to change notification settings - Fork 9.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
provider/azurerm: Scaffold the Azure RM Template Deployment resource
- Loading branch information
Showing
4 changed files
with
339 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
181 changes: 181 additions & 0 deletions
181
builtin/providers/azurerm/resource_arm_template_deployment.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
package azurerm | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"log" | ||
"net/http" | ||
"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, | ||
}, | ||
|
||
"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) | ||
deployment_mode := d.Get("deployment_mode").(string) | ||
|
||
log.Printf("[INFO] preparing arguments for Azure ARM Virtual Machine creation.") | ||
properties := resources.DeploymentProperties{ | ||
Mode: resources.DeploymentMode(deployment_mode), | ||
} | ||
|
||
if v, ok := d.GetOk("parameters"); ok { | ||
params := v.(map[string]interface{}) | ||
properties.Parameters = ¶ms | ||
} | ||
|
||
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 Deploymnet (%s) to become available", name) | ||
stateConf := &resource.StateChangeConf{ | ||
Pending: []string{"Creating", "Updating", "Accepted", "Running"}, | ||
Target: []string{"Succeeded"}, | ||
Refresh: templateDeploymentStateRefreshFunc(client, resGroup, name), | ||
Timeout: 10 * 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 Template Deployment %s: %s", name, err) | ||
} | ||
|
||
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("dont be a dumb fuck") | ||
} | ||
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, *res.Properties.ProvisioningState, nil | ||
} | ||
} |
148 changes: 148 additions & 0 deletions
148
builtin/providers/azurerm/resource_arm_template_deployment_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
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 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 = <<DEPLOY | ||
{ | ||
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", | ||
"contentVersion": "1.0.0.0", | ||
"parameters": { | ||
"storageAccountType": { | ||
"type": "string", | ||
"defaultValue": "Standard_LRS", | ||
"allowedValues": [ | ||
"Standard_LRS", | ||
"Standard_GRS", | ||
"Standard_ZRS" | ||
], | ||
"metadata": { | ||
"description": "Storage Account type" | ||
} | ||
} | ||
}, | ||
"variables": { | ||
"location": "[resourceGroup().location]", | ||
"storageAccountName": "[concat(uniquestring(resourceGroup().id), 'storage')]", | ||
"publicIPAddressName": "[concat('myPublicIp', uniquestring(resourceGroup().id))]", | ||
"publicIPAddressType": "Dynamic", | ||
"apiVersion": "2015-06-15", | ||
"dnsLabelPrefix": "terraform-acctest" | ||
}, | ||
"resources": [ | ||
{ | ||
"type": "Microsoft.Storage/storageAccounts", | ||
"name": "[variables('storageAccountName')]", | ||
"apiVersion": "[variables('apiVersion')]", | ||
"location": "[variables('location')]", | ||
"properties": { | ||
"accountType": "[parameters('storageAccountType')]" | ||
} | ||
}, | ||
{ | ||
"type": "Microsoft.Network/publicIPAddresses", | ||
"apiVersion": "[variables('apiVersion')]", | ||
"name": "[variables('publicIPAddressName')]", | ||
"location": "[variables('location')]", | ||
"properties": { | ||
"publicIPAllocationMethod": "[variables('publicIPAddressType')]", | ||
"dnsSettings": { | ||
"domainNameLabel": "[variables('dnsLabelPrefix')]" | ||
} | ||
} | ||
} | ||
] | ||
} | ||
DEPLOY | ||
deployment_mode = "Complete" | ||
} | ||
` |