provider/azurerm: Scaffold the Azure RM Template Deployment resource
This commit is contained in:
parent
fb92896326
commit
a4cd5eeb2b
|
@ -58,6 +58,8 @@ type ArmClient struct {
|
|||
|
||||
storageServiceClient storage.AccountsClient
|
||||
storageUsageClient storage.UsageOperationsClient
|
||||
|
||||
deploymentsClient resources.DeploymentsClient
|
||||
}
|
||||
|
||||
func withRequestLogging() autorest.SendDecorator {
|
||||
|
@ -295,6 +297,12 @@ func (c *Config) getArmClient() (*ArmClient, error) {
|
|||
cec.Sender = autorest.CreateSender(withRequestLogging())
|
||||
client.cdnEndpointsClient = cec
|
||||
|
||||
dc := resources.NewDeploymentsClient(c.SubscriptionID)
|
||||
setUserAgent(&dc.Client)
|
||||
dc.Authorizer = spt
|
||||
dc.Sender = autorest.CreateSender(withRequestLogging())
|
||||
client.deploymentsClient = dc
|
||||
|
||||
return &client, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -74,6 +74,7 @@ func Provider() terraform.ResourceProvider {
|
|||
"azurerm_storage_container": resourceArmStorageContainer(),
|
||||
"azurerm_storage_queue": resourceArmStorageQueue(),
|
||||
"azurerm_subnet": resourceArmSubnet(),
|
||||
"azurerm_template_deployment": resourceArmTemplateDeployment(),
|
||||
"azurerm_virtual_machine": resourceArmVirtualMachine(),
|
||||
"azurerm_virtual_network": resourceArmVirtualNetwork(),
|
||||
},
|
||||
|
@ -143,7 +144,7 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
|
|||
func registerAzureResourceProvidersWithSubscription(config *Config, client *ArmClient) error {
|
||||
providerClient := client.providers
|
||||
|
||||
providers := []string{"Microsoft.Network", "Microsoft.Compute", "Microsoft.Cdn", "Microsoft.Storage", "Microsoft.Sql", "Microsoft.Search"}
|
||||
providers := []string{"Microsoft.Network", "Microsoft.Compute", "Microsoft.Cdn", "Microsoft.Storage", "Microsoft.Sql", "Microsoft.Search", "Microsoft.Resources"}
|
||||
|
||||
for _, v := range providers {
|
||||
res, err := providerClient.Register(v)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
|
||||
`
|
Loading…
Reference in New Issue