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