github.com/koding/terraform@v0.6.4-0.20170608090606-5d7e0339779d/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 _, error := deployClient.CreateOrUpdate(resGroup, name, deployment, make(chan struct{})) 104 err := <-error 105 if err != nil { 106 return fmt.Errorf("Error creating deployment: %s", err) 107 } 108 109 read, err := deployClient.Get(resGroup, name) 110 if err != nil { 111 return err 112 } 113 if read.ID == nil { 114 return fmt.Errorf("Cannot read Template Deployment %s (resource group %s) ID", name, resGroup) 115 } 116 117 d.SetId(*read.ID) 118 119 log.Printf("[DEBUG] Waiting for Template Deployment (%s) to become available", name) 120 stateConf := &resource.StateChangeConf{ 121 Pending: []string{"creating", "updating", "accepted", "running"}, 122 Target: []string{"succeeded"}, 123 Refresh: templateDeploymentStateRefreshFunc(client, resGroup, name), 124 Timeout: 40 * time.Minute, 125 } 126 if _, err := stateConf.WaitForState(); err != nil { 127 return fmt.Errorf("Error waiting for Template Deployment (%s) to become available: %s", name, err) 128 } 129 130 return resourceArmTemplateDeploymentRead(d, meta) 131 } 132 133 func resourceArmTemplateDeploymentRead(d *schema.ResourceData, meta interface{}) error { 134 client := meta.(*ArmClient) 135 deployClient := client.deploymentsClient 136 137 id, err := parseAzureResourceID(d.Id()) 138 if err != nil { 139 return err 140 } 141 resGroup := id.ResourceGroup 142 name := id.Path["deployments"] 143 if name == "" { 144 name = id.Path["Deployments"] 145 } 146 147 resp, err := deployClient.Get(resGroup, name) 148 if err != nil { 149 if resp.StatusCode == http.StatusNotFound { 150 d.SetId("") 151 return nil 152 } 153 return fmt.Errorf("Error making Read request on Azure RM Template Deployment %s: %s", name, err) 154 } 155 156 var outputs map[string]string 157 if resp.Properties.Outputs != nil && len(*resp.Properties.Outputs) > 0 { 158 outputs = make(map[string]string) 159 for key, output := range *resp.Properties.Outputs { 160 log.Printf("[DEBUG] Processing deployment output %s", key) 161 outputMap := output.(map[string]interface{}) 162 outputValue, ok := outputMap["value"] 163 if !ok { 164 log.Printf("[DEBUG] No value - skipping") 165 continue 166 } 167 outputType, ok := outputMap["type"] 168 if !ok { 169 log.Printf("[DEBUG] No type - skipping") 170 continue 171 } 172 173 var outputValueString string 174 switch strings.ToLower(outputType.(string)) { 175 case "bool": 176 outputValueString = strconv.FormatBool(outputValue.(bool)) 177 178 case "string": 179 outputValueString = outputValue.(string) 180 181 case "int": 182 outputValueString = fmt.Sprint(outputValue) 183 184 default: 185 log.Printf("[WARN] Ignoring output %s: Outputs of type %s are not currently supported in azurerm_template_deployment.", 186 key, outputType) 187 continue 188 } 189 outputs[key] = outputValueString 190 } 191 } 192 193 return d.Set("outputs", outputs) 194 } 195 196 func resourceArmTemplateDeploymentDelete(d *schema.ResourceData, meta interface{}) error { 197 client := meta.(*ArmClient) 198 deployClient := client.deploymentsClient 199 200 id, err := parseAzureResourceID(d.Id()) 201 if err != nil { 202 return err 203 } 204 resGroup := id.ResourceGroup 205 name := id.Path["deployments"] 206 if name == "" { 207 name = id.Path["Deployments"] 208 } 209 210 _, error := deployClient.Delete(resGroup, name, make(chan struct{})) 211 err = <-error 212 213 return err 214 } 215 216 func expandTemplateBody(template string) (map[string]interface{}, error) { 217 var templateBody map[string]interface{} 218 err := json.Unmarshal([]byte(template), &templateBody) 219 if err != nil { 220 return nil, fmt.Errorf("Error Expanding the template_body for Azure RM Template Deployment") 221 } 222 return templateBody, nil 223 } 224 225 func normalizeJson(jsonString interface{}) string { 226 if jsonString == nil || jsonString == "" { 227 return "" 228 } 229 var j interface{} 230 err := json.Unmarshal([]byte(jsonString.(string)), &j) 231 if err != nil { 232 return fmt.Sprintf("Error parsing JSON: %s", err) 233 } 234 b, _ := json.Marshal(j) 235 return string(b[:]) 236 } 237 238 func templateDeploymentStateRefreshFunc(client *ArmClient, resourceGroupName string, name string) resource.StateRefreshFunc { 239 return func() (interface{}, string, error) { 240 res, err := client.deploymentsClient.Get(resourceGroupName, name) 241 if err != nil { 242 return nil, "", fmt.Errorf("Error issuing read request in templateDeploymentStateRefreshFunc to Azure ARM for Template Deployment '%s' (RG: '%s'): %s", name, resourceGroupName, err) 243 } 244 245 return res, strings.ToLower(*res.Properties.ProvisioningState), nil 246 } 247 }