github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/builtin/providers/azurerm/resource_arm_template_deployment.go (about) 1 package azurerm 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "log" 7 "net/http" 8 "strings" 9 "time" 10 11 "github.com/Azure/azure-sdk-for-go/arm/resources/resources" 12 "github.com/hashicorp/terraform/helper/resource" 13 "github.com/hashicorp/terraform/helper/schema" 14 ) 15 16 func resourceArmTemplateDeployment() *schema.Resource { 17 return &schema.Resource{ 18 Create: resourceArmTemplateDeploymentCreate, 19 Read: resourceArmTemplateDeploymentRead, 20 Update: resourceArmTemplateDeploymentCreate, 21 Delete: resourceArmTemplateDeploymentDelete, 22 23 Schema: map[string]*schema.Schema{ 24 "name": { 25 Type: schema.TypeString, 26 Required: true, 27 ForceNew: true, 28 }, 29 30 "resource_group_name": { 31 Type: schema.TypeString, 32 Required: true, 33 ForceNew: true, 34 }, 35 36 "template_body": { 37 Type: schema.TypeString, 38 Optional: true, 39 Computed: true, 40 StateFunc: normalizeJson, 41 }, 42 43 "parameters": { 44 Type: schema.TypeMap, 45 Optional: true, 46 }, 47 48 "outputs": { 49 Type: schema.TypeMap, 50 Computed: true, 51 }, 52 53 "deployment_mode": { 54 Type: schema.TypeString, 55 Required: true, 56 }, 57 }, 58 } 59 } 60 61 func resourceArmTemplateDeploymentCreate(d *schema.ResourceData, meta interface{}) error { 62 client := meta.(*ArmClient) 63 deployClient := client.deploymentsClient 64 65 name := d.Get("name").(string) 66 resGroup := d.Get("resource_group_name").(string) 67 deploymentMode := d.Get("deployment_mode").(string) 68 69 log.Printf("[INFO] preparing arguments for Azure ARM Template Deployment creation.") 70 properties := resources.DeploymentProperties{ 71 Mode: resources.DeploymentMode(deploymentMode), 72 } 73 74 if v, ok := d.GetOk("parameters"); ok { 75 params := v.(map[string]interface{}) 76 77 newParams := make(map[string]interface{}, len(params)) 78 for key, val := range params { 79 newParams[key] = struct { 80 Value interface{} 81 }{ 82 Value: val, 83 } 84 } 85 86 properties.Parameters = &newParams 87 } 88 89 if v, ok := d.GetOk("template_body"); ok { 90 template, err := expandTemplateBody(v.(string)) 91 if err != nil { 92 return err 93 } 94 95 properties.Template = &template 96 } 97 98 deployment := resources.Deployment{ 99 Properties: &properties, 100 } 101 102 _, err := deployClient.CreateOrUpdate(resGroup, name, deployment, make(chan struct{})) 103 if err != nil { 104 return fmt.Errorf("Error creating deployment: %s", err) 105 } 106 107 read, err := deployClient.Get(resGroup, name) 108 if err != nil { 109 return err 110 } 111 if read.ID == nil { 112 return fmt.Errorf("Cannot read Template Deployment %s (resource group %s) ID", name, resGroup) 113 } 114 115 d.SetId(*read.ID) 116 117 log.Printf("[DEBUG] Waiting for Template Deployment (%s) to become available", name) 118 stateConf := &resource.StateChangeConf{ 119 Pending: []string{"creating", "updating", "accepted", "running"}, 120 Target: []string{"succeeded"}, 121 Refresh: templateDeploymentStateRefreshFunc(client, resGroup, name), 122 Timeout: 40 * time.Minute, 123 } 124 if _, err := stateConf.WaitForState(); err != nil { 125 return fmt.Errorf("Error waiting for Template Deployment (%s) to become available: %s", name, err) 126 } 127 128 return resourceArmTemplateDeploymentRead(d, meta) 129 } 130 131 func resourceArmTemplateDeploymentRead(d *schema.ResourceData, meta interface{}) error { 132 client := meta.(*ArmClient) 133 deployClient := client.deploymentsClient 134 135 id, err := parseAzureResourceID(d.Id()) 136 if err != nil { 137 return err 138 } 139 resGroup := id.ResourceGroup 140 name := id.Path["deployments"] 141 if name == "" { 142 name = id.Path["Deployments"] 143 } 144 145 resp, err := deployClient.Get(resGroup, name) 146 if err != nil { 147 if resp.StatusCode == http.StatusNotFound { 148 d.SetId("") 149 return nil 150 } 151 return fmt.Errorf("Error making Read request on Azure RM Template Deployment %s: %s", name, err) 152 } 153 154 var outputs map[string]string 155 if resp.Properties.Outputs != nil && len(*resp.Properties.Outputs) > 0 { 156 outputs = make(map[string]string) 157 for key, output := range *resp.Properties.Outputs { 158 outputMap := output.(map[string]interface{}) 159 outputValue, ok := outputMap["value"] 160 if !ok { 161 // No value 162 continue 163 } 164 165 outputs[key] = outputValue.(string) 166 } 167 } 168 169 d.Set("outputs", outputs) 170 171 return nil 172 } 173 174 func resourceArmTemplateDeploymentDelete(d *schema.ResourceData, meta interface{}) error { 175 client := meta.(*ArmClient) 176 deployClient := client.deploymentsClient 177 178 id, err := parseAzureResourceID(d.Id()) 179 if err != nil { 180 return err 181 } 182 resGroup := id.ResourceGroup 183 name := id.Path["deployments"] 184 if name == "" { 185 name = id.Path["Deployments"] 186 } 187 188 _, err = deployClient.Delete(resGroup, name, make(chan struct{})) 189 return nil 190 } 191 192 func expandTemplateBody(template string) (map[string]interface{}, error) { 193 var templateBody map[string]interface{} 194 err := json.Unmarshal([]byte(template), &templateBody) 195 if err != nil { 196 return nil, fmt.Errorf("Error Expanding the template_body for Azure RM Template Deployment") 197 } 198 return templateBody, nil 199 } 200 201 func normalizeJson(jsonString interface{}) string { 202 if jsonString == nil || jsonString == "" { 203 return "" 204 } 205 var j interface{} 206 err := json.Unmarshal([]byte(jsonString.(string)), &j) 207 if err != nil { 208 return fmt.Sprintf("Error parsing JSON: %s", err) 209 } 210 b, _ := json.Marshal(j) 211 return string(b[:]) 212 } 213 214 func templateDeploymentStateRefreshFunc(client *ArmClient, resourceGroupName string, name string) resource.StateRefreshFunc { 215 return func() (interface{}, string, error) { 216 res, err := client.deploymentsClient.Get(resourceGroupName, name) 217 if err != nil { 218 return nil, "", fmt.Errorf("Error issuing read request in templateDeploymentStateRefreshFunc to Azure ARM for Template Deployment '%s' (RG: '%s'): %s", name, resourceGroupName, err) 219 } 220 221 return res, strings.ToLower(*res.Properties.ProvisioningState), nil 222 } 223 }