github.com/mohanarpit/terraform@v0.6.16-0.20160909104007-291f29853544/builtin/providers/aws/resource_aws_opsworks_application.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 "time" 8 9 "github.com/aws/aws-sdk-go/aws" 10 "github.com/aws/aws-sdk-go/aws/awserr" 11 "github.com/aws/aws-sdk-go/service/opsworks" 12 "github.com/hashicorp/terraform/helper/resource" 13 "github.com/hashicorp/terraform/helper/schema" 14 ) 15 16 func resourceAwsOpsworksApplication() *schema.Resource { 17 return &schema.Resource{ 18 19 Create: resourceAwsOpsworksApplicationCreate, 20 Read: resourceAwsOpsworksApplicationRead, 21 Update: resourceAwsOpsworksApplicationUpdate, 22 Delete: resourceAwsOpsworksApplicationDelete, 23 Schema: map[string]*schema.Schema{ 24 "id": &schema.Schema{ 25 Type: schema.TypeString, 26 Computed: true, 27 }, 28 "name": &schema.Schema{ 29 Type: schema.TypeString, 30 Required: true, 31 }, 32 "short_name": &schema.Schema{ 33 Type: schema.TypeString, 34 Computed: true, 35 Optional: true, 36 }, 37 // aws-flow-ruby | java | rails | php | nodejs | static | other 38 "type": &schema.Schema{ 39 Type: schema.TypeString, 40 Required: true, 41 }, 42 "stack_id": &schema.Schema{ 43 Type: schema.TypeString, 44 Required: true, 45 }, 46 // TODO: the following 4 vals are really part of the Attributes array. We should validate that only ones relevant to the chosen type are set, perhaps. (what is the default type? how do they map?) 47 "document_root": &schema.Schema{ 48 Type: schema.TypeString, 49 Optional: true, 50 //Default: "public", 51 }, 52 "rails_env": &schema.Schema{ 53 Type: schema.TypeString, 54 Optional: true, 55 //Default: "production", 56 }, 57 "auto_bundle_on_deploy": &schema.Schema{ 58 Type: schema.TypeString, 59 Optional: true, 60 //Default: true, 61 }, 62 "aws_flow_ruby_settings": &schema.Schema{ 63 Type: schema.TypeString, 64 Optional: true, 65 }, 66 "app_source": &schema.Schema{ 67 Type: schema.TypeList, 68 Optional: true, 69 Computed: true, 70 Elem: &schema.Resource{ 71 Schema: map[string]*schema.Schema{ 72 "type": &schema.Schema{ 73 Type: schema.TypeString, 74 Required: true, 75 }, 76 77 "url": &schema.Schema{ 78 Type: schema.TypeString, 79 Optional: true, 80 }, 81 82 "username": &schema.Schema{ 83 Type: schema.TypeString, 84 Optional: true, 85 }, 86 87 "password": &schema.Schema{ 88 Type: schema.TypeString, 89 Optional: true, 90 }, 91 92 "revision": &schema.Schema{ 93 Type: schema.TypeString, 94 Optional: true, 95 }, 96 97 "ssh_key": &schema.Schema{ 98 Type: schema.TypeString, 99 Optional: true, 100 }, 101 }, 102 }, 103 }, 104 // AutoSelectOpsworksMysqlInstance, OpsworksMysqlInstance, or RdsDbInstance. 105 // anything beside auto select will lead into failure in case the instance doesn't exist 106 // XXX: validation? 107 "data_source_type": &schema.Schema{ 108 Type: schema.TypeString, 109 Optional: true, 110 }, 111 "data_source_database_name": &schema.Schema{ 112 Type: schema.TypeString, 113 Optional: true, 114 }, 115 "data_source_arn": &schema.Schema{ 116 Type: schema.TypeString, 117 Optional: true, 118 }, 119 "description": &schema.Schema{ 120 Type: schema.TypeString, 121 Optional: true, 122 }, 123 "domains": &schema.Schema{ 124 Type: schema.TypeList, 125 Optional: true, 126 Elem: &schema.Schema{Type: schema.TypeString}, 127 }, 128 "environment": &schema.Schema{ 129 Type: schema.TypeSet, 130 Optional: true, 131 Elem: &schema.Resource{ 132 Schema: map[string]*schema.Schema{ 133 "key": &schema.Schema{ 134 Type: schema.TypeString, 135 Required: true, 136 }, 137 "value": &schema.Schema{ 138 Type: schema.TypeString, 139 Required: true, 140 }, 141 "secure": &schema.Schema{ 142 Type: schema.TypeBool, 143 Optional: true, 144 Default: true, 145 }, 146 }, 147 }, 148 }, 149 "enable_ssl": &schema.Schema{ 150 Type: schema.TypeBool, 151 Optional: true, 152 Default: false, 153 }, 154 "ssl_configuration": &schema.Schema{ 155 Type: schema.TypeList, 156 Optional: true, 157 //Computed: true, 158 Elem: &schema.Resource{ 159 Schema: map[string]*schema.Schema{ 160 "certificate": &schema.Schema{ 161 Type: schema.TypeString, 162 Required: true, 163 StateFunc: func(v interface{}) string { 164 switch v.(type) { 165 case string: 166 return strings.TrimSpace(v.(string)) 167 default: 168 return "" 169 } 170 }, 171 }, 172 "private_key": &schema.Schema{ 173 Type: schema.TypeString, 174 Required: true, 175 StateFunc: func(v interface{}) string { 176 switch v.(type) { 177 case string: 178 return strings.TrimSpace(v.(string)) 179 default: 180 return "" 181 } 182 }, 183 }, 184 "chain": &schema.Schema{ 185 Type: schema.TypeString, 186 Optional: true, 187 StateFunc: func(v interface{}) string { 188 switch v.(type) { 189 case string: 190 return strings.TrimSpace(v.(string)) 191 default: 192 return "" 193 } 194 }, 195 }, 196 }, 197 }, 198 }, 199 }, 200 } 201 } 202 203 func resourceAwsOpsworksApplicationValidate(d *schema.ResourceData) error { 204 appSourceCount := d.Get("app_source.#").(int) 205 if appSourceCount > 1 { 206 return fmt.Errorf("Only one app_source is permitted.") 207 } 208 209 sslCount := d.Get("ssl_configuration.#").(int) 210 if sslCount > 1 { 211 return fmt.Errorf("Only one ssl_configuration is permitted.") 212 } 213 214 if d.Get("type").(string) == opsworks.AppTypeRails { 215 if _, ok := d.GetOk("rails_env"); !ok { 216 return fmt.Errorf("Set rails_env must be set if type is set to rails.") 217 } 218 } 219 switch d.Get("type").(string) { 220 case opsworks.AppTypeStatic: 221 case opsworks.AppTypeRails: 222 case opsworks.AppTypePhp: 223 case opsworks.AppTypeOther: 224 case opsworks.AppTypeNodejs: 225 case opsworks.AppTypeJava: 226 case opsworks.AppTypeAwsFlowRuby: 227 log.Printf("[DEBUG] type supported") 228 default: 229 return fmt.Errorf("opsworks_application.type must be one of %s, %s, %s, %s, %s, %s, %s", 230 opsworks.AppTypeStatic, 231 opsworks.AppTypeRails, 232 opsworks.AppTypePhp, 233 opsworks.AppTypeOther, 234 opsworks.AppTypeNodejs, 235 opsworks.AppTypeJava, 236 opsworks.AppTypeAwsFlowRuby) 237 } 238 239 return nil 240 } 241 242 func resourceAwsOpsworksApplicationRead(d *schema.ResourceData, meta interface{}) error { 243 client := meta.(*AWSClient).opsworksconn 244 245 req := &opsworks.DescribeAppsInput{ 246 AppIds: []*string{ 247 aws.String(d.Id()), 248 }, 249 } 250 251 log.Printf("[DEBUG] Reading OpsWorks app: %s", d.Id()) 252 253 resp, err := client.DescribeApps(req) 254 if err != nil { 255 if awserr, ok := err.(awserr.Error); ok { 256 if awserr.Code() == "ResourceNotFoundException" { 257 log.Printf("[INFO] App not found: %s", d.Id()) 258 d.SetId("") 259 return nil 260 } 261 } 262 return err 263 } 264 265 app := resp.Apps[0] 266 267 d.Set("name", app.Name) 268 d.Set("stack_id", app.StackId) 269 d.Set("type", app.Type) 270 d.Set("description", app.Description) 271 d.Set("domains", flattenStringList(app.Domains)) 272 d.Set("enable_ssl", app.EnableSsl) 273 resourceAwsOpsworksSetApplicationSsl(d, app.SslConfiguration) 274 resourceAwsOpsworksSetApplicationSource(d, app.AppSource) 275 resourceAwsOpsworksSetApplicationDataSources(d, app.DataSources) 276 resourceAwsOpsworksSetApplicationEnvironmentVariable(d, app.Environment) 277 resourceAwsOpsworksSetApplicationAttributes(d, app.Attributes) 278 return nil 279 } 280 281 func resourceAwsOpsworksApplicationCreate(d *schema.ResourceData, meta interface{}) error { 282 client := meta.(*AWSClient).opsworksconn 283 284 err := resourceAwsOpsworksApplicationValidate(d) 285 if err != nil { 286 return err 287 } 288 289 req := &opsworks.CreateAppInput{ 290 Name: aws.String(d.Get("name").(string)), 291 Shortname: aws.String(d.Get("short_name").(string)), 292 StackId: aws.String(d.Get("stack_id").(string)), 293 Type: aws.String(d.Get("type").(string)), 294 Description: aws.String(d.Get("description").(string)), 295 Domains: expandStringList(d.Get("domains").([]interface{})), 296 EnableSsl: aws.Bool(d.Get("enable_ssl").(bool)), 297 SslConfiguration: resourceAwsOpsworksApplicationSsl(d), 298 AppSource: resourceAwsOpsworksApplicationSource(d), 299 DataSources: resourceAwsOpsworksApplicationDataSources(d), 300 Environment: resourceAwsOpsworksApplicationEnvironmentVariable(d), 301 Attributes: resourceAwsOpsworksApplicationAttributes(d), 302 } 303 304 var resp *opsworks.CreateAppOutput 305 err = resource.Retry(2*time.Minute, func() *resource.RetryError { 306 var cerr error 307 resp, cerr = client.CreateApp(req) 308 if cerr != nil { 309 log.Printf("[INFO] client error") 310 if opserr, ok := cerr.(awserr.Error); ok { 311 // XXX: handle errors 312 log.Printf("[ERROR] OpsWorks error: %s message: %s", opserr.Code(), opserr.Message()) 313 return resource.RetryableError(cerr) 314 } 315 return resource.NonRetryableError(cerr) 316 } 317 return nil 318 }) 319 320 if err != nil { 321 return err 322 } 323 324 appID := *resp.AppId 325 d.SetId(appID) 326 d.Set("id", appID) 327 328 return resourceAwsOpsworksApplicationRead(d, meta) 329 } 330 331 func resourceAwsOpsworksApplicationUpdate(d *schema.ResourceData, meta interface{}) error { 332 client := meta.(*AWSClient).opsworksconn 333 334 req := &opsworks.UpdateAppInput{ 335 AppId: aws.String(d.Id()), 336 Name: aws.String(d.Get("name").(string)), 337 Type: aws.String(d.Get("type").(string)), 338 Description: aws.String(d.Get("description").(string)), 339 Domains: expandStringList(d.Get("domains").([]interface{})), 340 EnableSsl: aws.Bool(d.Get("enable_ssl").(bool)), 341 SslConfiguration: resourceAwsOpsworksApplicationSsl(d), 342 AppSource: resourceAwsOpsworksApplicationSource(d), 343 DataSources: resourceAwsOpsworksApplicationDataSources(d), 344 Environment: resourceAwsOpsworksApplicationEnvironmentVariable(d), 345 Attributes: resourceAwsOpsworksApplicationAttributes(d), 346 } 347 348 log.Printf("[DEBUG] Updating OpsWorks layer: %s", d.Id()) 349 350 err := resource.Retry(2*time.Minute, func() *resource.RetryError { 351 _, cerr := client.UpdateApp(req) 352 if cerr != nil { 353 log.Printf("[INFO] client error") 354 if opserr, ok := cerr.(awserr.Error); ok { 355 // XXX: handle errors 356 log.Printf("[ERROR] OpsWorks error: %s message: %s", opserr.Code(), opserr.Message()) 357 return resource.NonRetryableError(cerr) 358 } 359 return resource.RetryableError(cerr) 360 } 361 return nil 362 }) 363 364 if err != nil { 365 return err 366 } 367 return resourceAwsOpsworksApplicationRead(d, meta) 368 } 369 370 func resourceAwsOpsworksApplicationDelete(d *schema.ResourceData, meta interface{}) error { 371 client := meta.(*AWSClient).opsworksconn 372 373 req := &opsworks.DeleteAppInput{ 374 AppId: aws.String(d.Id()), 375 } 376 377 log.Printf("[DEBUG] Deleting OpsWorks application: %s", d.Id()) 378 379 _, err := client.DeleteApp(req) 380 return err 381 } 382 383 func resourceAwsOpsworksSetApplicationEnvironmentVariable(d *schema.ResourceData, v []*opsworks.EnvironmentVariable) { 384 log.Printf("[DEBUG] envs: %s %d", v, len(v)) 385 if len(v) == 0 { 386 d.Set("environment", nil) 387 return 388 } 389 newValue := make([]*map[string]interface{}, len(v)) 390 391 for i := 0; i < len(v); i++ { 392 config := v[i] 393 data := make(map[string]interface{}) 394 newValue[i] = &data 395 396 if config.Key != nil { 397 data["key"] = *config.Key 398 } 399 if config.Value != nil { 400 data["value"] = *config.Value 401 } 402 if config.Secure != nil { 403 404 if bool(*config.Secure) { 405 data["secure"] = &opsworksTrueString 406 } else { 407 data["secure"] = &opsworksFalseString 408 } 409 } 410 log.Printf("[DEBUG] v: %s", data) 411 } 412 413 d.Set("environment", newValue) 414 } 415 416 func resourceAwsOpsworksApplicationEnvironmentVariable(d *schema.ResourceData) []*opsworks.EnvironmentVariable { 417 environmentVariables := d.Get("environment").(*schema.Set).List() 418 result := make([]*opsworks.EnvironmentVariable, len(environmentVariables)) 419 420 for i := 0; i < len(environmentVariables); i++ { 421 env := environmentVariables[i].(map[string]interface{}) 422 423 result[i] = &opsworks.EnvironmentVariable{ 424 Key: aws.String(env["key"].(string)), 425 Value: aws.String(env["value"].(string)), 426 Secure: aws.Bool(env["secure"].(bool)), 427 } 428 } 429 return result 430 } 431 432 func resourceAwsOpsworksApplicationSource(d *schema.ResourceData) *opsworks.Source { 433 count := d.Get("app_source.#").(int) 434 if count == 0 { 435 return nil 436 } 437 438 return &opsworks.Source{ 439 Type: aws.String(d.Get("app_source.0.type").(string)), 440 Url: aws.String(d.Get("app_source.0.url").(string)), 441 Username: aws.String(d.Get("app_source.0.username").(string)), 442 Password: aws.String(d.Get("app_source.0.password").(string)), 443 Revision: aws.String(d.Get("app_source.0.revision").(string)), 444 SshKey: aws.String(d.Get("app_source.0.ssh_key").(string)), 445 } 446 } 447 448 func resourceAwsOpsworksSetApplicationSource(d *schema.ResourceData, v *opsworks.Source) { 449 nv := make([]interface{}, 0, 1) 450 if v != nil { 451 m := make(map[string]interface{}) 452 if v.Type != nil { 453 m["type"] = *v.Type 454 } 455 if v.Url != nil { 456 m["url"] = *v.Url 457 } 458 if v.Username != nil { 459 m["username"] = *v.Username 460 } 461 if v.Password != nil { 462 m["password"] = *v.Password 463 } 464 if v.Revision != nil { 465 m["revision"] = *v.Revision 466 } 467 nv = append(nv, m) 468 } 469 470 err := d.Set("app_source", nv) 471 if err != nil { 472 // should never happen 473 panic(err) 474 } 475 } 476 477 func resourceAwsOpsworksApplicationDataSources(d *schema.ResourceData) []*opsworks.DataSource { 478 arn := d.Get("data_source_arn").(string) 479 databaseName := d.Get("data_source_database_name").(string) 480 databaseType := d.Get("data_source_type").(string) 481 482 result := make([]*opsworks.DataSource, 1) 483 484 if len(arn) > 0 || len(databaseName) > 0 || len(databaseType) > 0 { 485 result[0] = &opsworks.DataSource{ 486 Arn: aws.String(arn), 487 DatabaseName: aws.String(databaseName), 488 Type: aws.String(databaseType), 489 } 490 } 491 return result 492 } 493 494 func resourceAwsOpsworksSetApplicationDataSources(d *schema.ResourceData, v []*opsworks.DataSource) { 495 d.Set("data_source_arn", nil) 496 d.Set("data_source_database_name", nil) 497 d.Set("data_source_type", nil) 498 499 if len(v) == 0 { 500 return 501 } 502 503 d.Set("data_source_arn", v[0].Arn) 504 d.Set("data_source_database_name", v[0].DatabaseName) 505 d.Set("data_source_type", v[0].Type) 506 } 507 508 func resourceAwsOpsworksApplicationSsl(d *schema.ResourceData) *opsworks.SslConfiguration { 509 count := d.Get("ssl_configuration.#").(int) 510 if count == 0 { 511 return nil 512 } 513 514 return &opsworks.SslConfiguration{ 515 PrivateKey: aws.String(d.Get("ssl_configuration.0.private_key").(string)), 516 Certificate: aws.String(d.Get("ssl_configuration.0.certificate").(string)), 517 Chain: aws.String(d.Get("ssl_configuration.0.chain").(string)), 518 } 519 } 520 521 func resourceAwsOpsworksSetApplicationSsl(d *schema.ResourceData, v *opsworks.SslConfiguration) { 522 nv := make([]interface{}, 0, 1) 523 set := false 524 if v != nil { 525 m := make(map[string]interface{}) 526 if v.PrivateKey != nil { 527 m["private_key"] = *v.PrivateKey 528 set = true 529 } 530 if v.Certificate != nil { 531 m["certificate"] = *v.Certificate 532 set = true 533 } 534 if v.Chain != nil { 535 m["chain"] = *v.Chain 536 set = true 537 } 538 if set { 539 nv = append(nv, m) 540 } 541 } 542 543 err := d.Set("ssl_configuration", nv) 544 if err != nil { 545 // should never happen 546 panic(err) 547 } 548 } 549 550 func resourceAwsOpsworksApplicationAttributes(d *schema.ResourceData) map[string]*string { 551 if d.Get("type") != opsworks.AppTypeRails { 552 return nil 553 } 554 attributes := make(map[string]*string) 555 556 if val := d.Get("document_root").(string); len(val) > 0 { 557 attributes[opsworks.AppAttributesKeysDocumentRoot] = aws.String(val) 558 } 559 if val := d.Get("aws_flow_ruby_settings").(string); len(val) > 0 { 560 attributes[opsworks.AppAttributesKeysAwsFlowRubySettings] = aws.String(val) 561 } 562 if val := d.Get("rails_env").(string); len(val) > 0 { 563 attributes[opsworks.AppAttributesKeysRailsEnv] = aws.String(val) 564 } 565 if val := d.Get("auto_bundle_on_deploy").(string); len(val) > 0 { 566 if val == "1" { 567 val = "true" 568 } else if val == "0" { 569 val = "false" 570 } 571 attributes[opsworks.AppAttributesKeysAutoBundleOnDeploy] = aws.String(val) 572 } 573 574 return attributes 575 } 576 577 func resourceAwsOpsworksSetApplicationAttributes(d *schema.ResourceData, v map[string]*string) { 578 d.Set("document_root", nil) 579 d.Set("rails_env", nil) 580 d.Set("aws_flow_ruby_settings", nil) 581 d.Set("auto_bundle_on_deploy", nil) 582 583 if d.Get("type") != opsworks.AppTypeRails { 584 return 585 } 586 if val, ok := v[opsworks.AppAttributesKeysDocumentRoot]; ok { 587 d.Set("document_root", val) 588 } 589 if val, ok := v[opsworks.AppAttributesKeysAwsFlowRubySettings]; ok { 590 d.Set("aws_flow_ruby_settings", val) 591 } 592 if val, ok := v[opsworks.AppAttributesKeysRailsEnv]; ok { 593 d.Set("rails_env", val) 594 } 595 if val, ok := v[opsworks.AppAttributesKeysAutoBundleOnDeploy]; ok { 596 d.Set("auto_bundle_on_deploy", val) 597 } 598 }