diff --git a/builtin/providers/aws/config.go b/builtin/providers/aws/config.go index f462810fc1..2260a548a7 100644 --- a/builtin/providers/aws/config.go +++ b/builtin/providers/aws/config.go @@ -22,6 +22,7 @@ import ( "github.com/aws/aws-sdk-go/service/iam" "github.com/aws/aws-sdk-go/service/kinesis" "github.com/aws/aws-sdk-go/service/lambda" + "github.com/aws/aws-sdk-go/service/opsworks" "github.com/aws/aws-sdk-go/service/rds" "github.com/aws/aws-sdk-go/service/route53" "github.com/aws/aws-sdk-go/service/s3" @@ -61,6 +62,7 @@ type AWSClient struct { kinesisconn *kinesis.Kinesis elasticacheconn *elasticache.ElastiCache lambdaconn *lambda.Lambda + opsworksconn *opsworks.OpsWorks } // Client configures and returns a fully initialized AWSClient @@ -106,6 +108,16 @@ func (c *Config) Client() (interface{}, error) { MaxRetries: aws.Int(c.MaxRetries), Endpoint: aws.String(c.DynamoDBEndpoint), } + // Some services exist only in us-east-1, e.g. because they manage + // resources that can span across multiple regions, or because + // signature format v4 requires region to be us-east-1 for global + // endpoints: + // http://docs.aws.amazon.com/general/latest/gr/sigv4_changes.html + usEast1AwsConfig := &aws.Config{ + Credentials: creds, + Region: aws.String("us-east-1"), + MaxRetries: aws.Int(c.MaxRetries), + } log.Println("[INFO] Initializing DynamoDB connection") client.dynamodbconn = dynamodb.New(awsDynamoDBConfig) @@ -145,15 +157,8 @@ func (c *Config) Client() (interface{}, error) { log.Println("[INFO] Initializing EFS Connection") client.efsconn = efs.New(awsConfig) - // aws-sdk-go uses v4 for signing requests, which requires all global - // endpoints to use 'us-east-1'. - // See http://docs.aws.amazon.com/general/latest/gr/sigv4_changes.html log.Println("[INFO] Initializing Route 53 connection") - client.r53conn = route53.New(&aws.Config{ - Credentials: creds, - Region: aws.String("us-east-1"), - MaxRetries: aws.Int(c.MaxRetries), - }) + client.r53conn = route53.New(usEast1AwsConfig) log.Println("[INFO] Initializing Elasticache Connection") client.elasticacheconn = elasticache.New(awsConfig) @@ -166,6 +171,9 @@ func (c *Config) Client() (interface{}, error) { log.Println("[INFO] Initializing CloudWatch Logs connection") client.cloudwatchlogsconn = cloudwatchlogs.New(awsConfig) + + log.Println("[INFO] Initializing OpsWorks Connection") + client.opsworksconn = opsworks.New(usEast1AwsConfig) } if len(errs) > 0 { diff --git a/builtin/providers/aws/conversions.go b/builtin/providers/aws/conversions.go new file mode 100644 index 0000000000..7911237459 --- /dev/null +++ b/builtin/providers/aws/conversions.go @@ -0,0 +1,33 @@ +package aws + +import ( + "github.com/awslabs/aws-sdk-go/aws" + "github.com/hashicorp/terraform/helper/schema" +) + +func makeAwsStringList(in []interface {}) []*string { + ret := make([]*string, len(in), len(in)) + for i := 0; i < len(in); i++ { + ret[i] = aws.String(in[i].(string)) + } + return ret +} + +func makeAwsStringSet(in *schema.Set) []*string { + inList := in.List() + ret := make([]*string, len(inList), len(inList)) + for i := 0; i < len(ret); i++ { + ret[i] = aws.String(inList[i].(string)) + } + return ret +} + +func unwrapAwsStringList(in []*string) []string { + ret := make([]string, len(in), len(in)) + for i := 0; i < len(in); i++ { + if in[i] != nil { + ret[i] = *(in[i]) + } + } + return ret +} diff --git a/builtin/providers/aws/opsworks_layers.go b/builtin/providers/aws/opsworks_layers.go new file mode 100644 index 0000000000..4ad9382eb0 --- /dev/null +++ b/builtin/providers/aws/opsworks_layers.go @@ -0,0 +1,558 @@ +package aws + +import ( + "fmt" + "log" + "strconv" + + "github.com/hashicorp/terraform/helper/hashcode" + "github.com/hashicorp/terraform/helper/schema" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/opsworks" +) + +// OpsWorks has a single concept of "layer" which represents several different +// layer types. The differences between these are in some extra properties that +// get packed into an "Attributes" map, but in the OpsWorks UI these are presented +// as first-class options, and so Terraform prefers to expose them this way and +// hide the implementation detail that they are all packed into a single type +// in the underlying API. +// +// This file contains utilities that are shared between all of the concrete +// layer resource types, which have names matching aws_opsworks_*_layer . + +type opsworksLayerTypeAttribute struct { + AttrName string + Type schema.ValueType + Default interface{} + Required bool + WriteOnly bool +} + +type opsworksLayerType struct { + TypeName string + DefaultLayerName string + Attributes map[string]*opsworksLayerTypeAttribute + CustomShortName bool +} + +var ( + opsworksTrueString = "1" + opsworksFalseString = "0" +) + +func (lt *opsworksLayerType) SchemaResource() *schema.Resource { + resourceSchema := map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + + "auto_assign_elastic_ips": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + + "auto_assign_public_ips": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + + "custom_instance_profile_arn": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + + "custom_setup_recipes": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + "custom_configure_recipes": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + "custom_deploy_recipes": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + "custom_undeploy_recipes": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + "custom_shutdown_recipes": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + "custom_security_group_ids": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + + "auto_healing": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + + "install_updates_on_boot": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + + "instance_shutdown_timeout": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Default: 120, + }, + + "drain_elb_on_shutdown": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + + "system_packages": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + + "stack_id": &schema.Schema{ + Type: schema.TypeString, + ForceNew: true, + Required: true, + }, + + "use_ebs_optimized_instances": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + + "ebs_volume": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + + "iops": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Default: 0, + }, + + "mount_point": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + + "number_of_disks": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + + "raid_level": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "", + }, + + "size": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + }, + + "type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "standard", + }, + }, + }, + Set: func(v interface{}) int { + m := v.(map[string]interface{}) + return hashcode.String(m["mount_point"].(string)) + }, + }, + } + + if lt.CustomShortName { + resourceSchema["short_name"] = &schema.Schema{ + Type: schema.TypeString, + Required: true, + } + } + + if lt.DefaultLayerName != "" { + resourceSchema["name"] = &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: lt.DefaultLayerName, + } + } else { + resourceSchema["name"] = &schema.Schema{ + Type: schema.TypeString, + Required: true, + } + } + + for key, def := range lt.Attributes { + resourceSchema[key] = &schema.Schema{ + Type: def.Type, + Default: def.Default, + Required: def.Required, + Optional: !def.Required, + } + } + + return &schema.Resource{ + Read: func(d *schema.ResourceData, meta interface{}) error { + client := meta.(*AWSClient).opsworksconn + return lt.Read(d, client) + }, + Create: func(d *schema.ResourceData, meta interface{}) error { + client := meta.(*AWSClient).opsworksconn + return lt.Create(d, client) + }, + Update: func(d *schema.ResourceData, meta interface{}) error { + client := meta.(*AWSClient).opsworksconn + return lt.Update(d, client) + }, + Delete: func(d *schema.ResourceData, meta interface{}) error { + client := meta.(*AWSClient).opsworksconn + return lt.Delete(d, client) + }, + + Schema: resourceSchema, + } +} + +func (lt *opsworksLayerType) Read(d *schema.ResourceData, client *opsworks.OpsWorks) error { + + req := &opsworks.DescribeLayersInput{ + LayerIds: []*string{ + aws.String(d.Id()), + }, + } + + log.Printf("[DEBUG] Reading OpsWorks layer: %s", d.Id()) + + resp, err := client.DescribeLayers(req) + if err != nil { + if awserr, ok := err.(awserr.Error); ok { + if awserr.Code() == "ResourceNotFoundException" { + d.SetId("") + return nil + } + } + return err + } + + layer := resp.Layers[0] + d.Set("id", layer.LayerId) + d.Set("auto_assign_elastic_ips", layer.AutoAssignElasticIps) + d.Set("auto_assign_public_ips", layer.AutoAssignPublicIps) + d.Set("custom_instance_profile_arn", layer.CustomInstanceProfileArn) + d.Set("custom_security_group_ids", unwrapAwsStringList(layer.CustomSecurityGroupIds)) + d.Set("auto_healing", layer.EnableAutoHealing) + d.Set("install_updates_on_boot", layer.InstallUpdatesOnBoot) + d.Set("name", layer.Name) + d.Set("system_packages", unwrapAwsStringList(layer.Packages)) + d.Set("stack_id", layer.StackId) + d.Set("use_ebs_optimized_instances", layer.UseEbsOptimizedInstances) + + if lt.CustomShortName { + d.Set("short_name", layer.Shortname) + } + + lt.SetAttributeMap(d, layer.Attributes) + lt.SetLifecycleEventConfiguration(d, layer.LifecycleEventConfiguration) + lt.SetCustomRecipes(d, layer.CustomRecipes) + lt.SetVolumeConfigurations(d, layer.VolumeConfigurations) + + return nil +} + +func (lt *opsworksLayerType) Create(d *schema.ResourceData, client *opsworks.OpsWorks) error { + + req := &opsworks.CreateLayerInput{ + AutoAssignElasticIps: aws.Bool(d.Get("auto_assign_elastic_ips").(bool)), + AutoAssignPublicIps: aws.Bool(d.Get("auto_assign_public_ips").(bool)), + CustomInstanceProfileArn: aws.String(d.Get("custom_instance_profile_arn").(string)), + CustomRecipes: lt.CustomRecipes(d), + CustomSecurityGroupIds: makeAwsStringSet(d.Get("custom_security_group_ids").(*schema.Set)), + EnableAutoHealing: aws.Bool(d.Get("auto_healing").(bool)), + InstallUpdatesOnBoot: aws.Bool(d.Get("install_updates_on_boot").(bool)), + LifecycleEventConfiguration: lt.LifecycleEventConfiguration(d), + Name: aws.String(d.Get("name").(string)), + Packages: makeAwsStringSet(d.Get("system_packages").(*schema.Set)), + Type: aws.String(lt.TypeName), + StackId: aws.String(d.Get("stack_id").(string)), + UseEbsOptimizedInstances: aws.Bool(d.Get("use_ebs_optimized_instances").(bool)), + Attributes: lt.AttributeMap(d), + VolumeConfigurations: lt.VolumeConfigurations(d), + } + + if lt.CustomShortName { + req.Shortname = aws.String(d.Get("short_name").(string)) + } else { + req.Shortname = aws.String(lt.TypeName) + } + + log.Printf("[DEBUG] Creating OpsWorks layer: %s", d.Id()) + + resp, err := client.CreateLayer(req) + if err != nil { + return err + } + + layerId := *resp.LayerId + d.SetId(layerId) + d.Set("id", layerId) + + return lt.Read(d, client) +} + +func (lt *opsworksLayerType) Update(d *schema.ResourceData, client *opsworks.OpsWorks) error { + + req := &opsworks.UpdateLayerInput{ + LayerId: aws.String(d.Id()), + AutoAssignElasticIps: aws.Bool(d.Get("auto_assign_elastic_ips").(bool)), + AutoAssignPublicIps: aws.Bool(d.Get("auto_assign_public_ips").(bool)), + CustomInstanceProfileArn: aws.String(d.Get("custom_instance_profile_arn").(string)), + CustomRecipes: lt.CustomRecipes(d), + CustomSecurityGroupIds: makeAwsStringSet(d.Get("custom_security_group_ids").(*schema.Set)), + EnableAutoHealing: aws.Bool(d.Get("auto_healing").(bool)), + InstallUpdatesOnBoot: aws.Bool(d.Get("install_updates_on_boot").(bool)), + LifecycleEventConfiguration: lt.LifecycleEventConfiguration(d), + Name: aws.String(d.Get("name").(string)), + Packages: makeAwsStringSet(d.Get("system_packages").(*schema.Set)), + UseEbsOptimizedInstances: aws.Bool(d.Get("use_ebs_optimized_instances").(bool)), + Attributes: lt.AttributeMap(d), + VolumeConfigurations: lt.VolumeConfigurations(d), + } + + if lt.CustomShortName { + req.Shortname = aws.String(d.Get("short_name").(string)) + } else { + req.Shortname = aws.String(lt.TypeName) + } + + log.Printf("[DEBUG] Updating OpsWorks layer: %s", d.Id()) + + _, err := client.UpdateLayer(req) + if err != nil { + return err + } + + return lt.Read(d, client) +} + +func (lt *opsworksLayerType) Delete(d *schema.ResourceData, client *opsworks.OpsWorks) error { + req := &opsworks.DeleteLayerInput{ + LayerId: aws.String(d.Id()), + } + + log.Printf("[DEBUG] Deleting OpsWorks layer: %s", d.Id()) + + _, err := client.DeleteLayer(req) + return err +} + +func (lt *opsworksLayerType) AttributeMap(d *schema.ResourceData) map[string]*string { + attrs := map[string]*string{} + + for key, def := range lt.Attributes { + value := d.Get(key) + switch def.Type { + case schema.TypeString: + strValue := value.(string) + attrs[def.AttrName] = &strValue + case schema.TypeInt: + intValue := value.(int) + strValue := strconv.Itoa(intValue) + attrs[def.AttrName] = &strValue + case schema.TypeBool: + boolValue := value.(bool) + if boolValue { + attrs[def.AttrName] = &opsworksTrueString + } else { + attrs[def.AttrName] = &opsworksFalseString + } + default: + // should never happen + panic(fmt.Errorf("Unsupported OpsWorks layer attribute type")) + } + } + + return attrs +} + +func (lt *opsworksLayerType) SetAttributeMap(d *schema.ResourceData, attrs map[string]*string) { + for key, def := range lt.Attributes { + // Ignore write-only attributes; we'll just keep what we already have stored. + // (The AWS API returns garbage placeholder values for these.) + if def.WriteOnly { + continue + } + + if strPtr, ok := attrs[def.AttrName]; ok && strPtr != nil { + strValue := *strPtr + + switch def.Type { + case schema.TypeString: + d.Set(key, strValue) + case schema.TypeInt: + intValue, err := strconv.Atoi(strValue) + if err == nil { + d.Set(key, intValue) + } else { + // Got garbage from the AWS API + d.Set(key, nil) + } + case schema.TypeBool: + boolValue := true + if strValue == opsworksFalseString { + boolValue = false + } + d.Set(key, boolValue) + default: + // should never happen + panic(fmt.Errorf("Unsupported OpsWorks layer attribute type")) + } + return + + } else { + d.Set(key, nil) + } + } +} + +func (lt *opsworksLayerType) LifecycleEventConfiguration(d *schema.ResourceData) *opsworks.LifecycleEventConfiguration { + return &opsworks.LifecycleEventConfiguration{ + Shutdown: &opsworks.ShutdownEventConfiguration{ + DelayUntilElbConnectionsDrained: aws.Bool(d.Get("drain_elb_on_shutdown").(bool)), + ExecutionTimeout: aws.Int64(int64(d.Get("instance_shutdown_timeout").(int))), + }, + } +} + +func (lt *opsworksLayerType) SetLifecycleEventConfiguration(d *schema.ResourceData, v *opsworks.LifecycleEventConfiguration) { + if v == nil || v.Shutdown == nil { + d.Set("drain_elb_on_shutdown", nil) + d.Set("instance_shutdown_timeout", nil) + } else { + d.Set("drain_elb_on_shutdown", v.Shutdown.DelayUntilElbConnectionsDrained) + d.Set("instance_shutdown_timeout", v.Shutdown.ExecutionTimeout) + } +} + +func (lt *opsworksLayerType) CustomRecipes(d *schema.ResourceData) *opsworks.Recipes { + return &opsworks.Recipes{ + Configure: makeAwsStringList(d.Get("custom_configure_recipes").([]interface{})), + Deploy: makeAwsStringList(d.Get("custom_deploy_recipes").([]interface{})), + Setup: makeAwsStringList(d.Get("custom_setup_recipes").([]interface{})), + Shutdown: makeAwsStringList(d.Get("custom_shutdown_recipes").([]interface{})), + Undeploy: makeAwsStringList(d.Get("custom_undeploy_recipes").([]interface{})), + } +} + +func (lt *opsworksLayerType) SetCustomRecipes(d *schema.ResourceData, v *opsworks.Recipes) { + // Null out everything first, and then we'll consider what to put back. + d.Set("custom_configure_recipes", nil) + d.Set("custom_deploy_recipes", nil) + d.Set("custom_setup_recipes", nil) + d.Set("custom_shutdown_recipes", nil) + d.Set("custom_undeploy_recipes", nil) + + if v == nil { + return + } + + d.Set("custom_configure_recipes", unwrapAwsStringList(v.Configure)) + d.Set("custom_deploy_recipes", unwrapAwsStringList(v.Deploy)) + d.Set("custom_setup_recipes", unwrapAwsStringList(v.Setup)) + d.Set("custom_shutdown_recipes", unwrapAwsStringList(v.Shutdown)) + d.Set("custom_undeploy_recipes", unwrapAwsStringList(v.Undeploy)) +} + +func (lt *opsworksLayerType) VolumeConfigurations(d *schema.ResourceData) []*opsworks.VolumeConfiguration { + configuredVolumes := d.Get("ebs_volume").(*schema.Set).List() + result := make([]*opsworks.VolumeConfiguration, len(configuredVolumes)) + + for i := 0; i < len(configuredVolumes); i++ { + volumeData := configuredVolumes[i].(map[string]interface{}) + + result[i] = &opsworks.VolumeConfiguration{ + MountPoint: aws.String(volumeData["mount_point"].(string)), + NumberOfDisks: aws.Int64(int64(volumeData["number_of_disks"].(int))), + Size: aws.Int64(int64(volumeData["size"].(int))), + VolumeType: aws.String(volumeData["type"].(string)), + } + iops := int64(volumeData["iops"].(int)) + if iops != 0 { + result[i].Iops = aws.Int64(iops) + } + + raidLevelStr := volumeData["raid_level"].(string) + if raidLevelStr != "" { + raidLevel, err := strconv.Atoi(raidLevelStr) + if err == nil { + result[i].RaidLevel = aws.Int64(int64(raidLevel)) + } + } + } + + return result +} + +func (lt *opsworksLayerType) SetVolumeConfigurations(d *schema.ResourceData, v []*opsworks.VolumeConfiguration) { + newValue := make([]*map[string]interface{}, len(v)) + + for i := 0; i < len(v); i++ { + config := v[i] + data := make(map[string]interface{}) + newValue[i] = &data + + if config.Iops != nil { + data["iops"] = int(*config.Iops) + } else { + data["iops"] = 0 + } + if config.MountPoint != nil { + data["mount_point"] = *config.MountPoint + } + if config.NumberOfDisks != nil { + data["number_of_disks"] = int(*config.NumberOfDisks) + } + if config.RaidLevel != nil { + data["raid_level"] = strconv.Itoa(int(*config.RaidLevel)) + } + if config.Size != nil { + data["size"] = int(*config.Size) + } + if config.VolumeType != nil { + data["type"] = *config.VolumeType + } + } + + d.Set("ebs_volume", newValue) +} diff --git a/builtin/providers/aws/provider.go b/builtin/providers/aws/provider.go index 350aeb75da..3b5aa67ad4 100644 --- a/builtin/providers/aws/provider.go +++ b/builtin/providers/aws/provider.go @@ -207,6 +207,17 @@ func Provider() terraform.ResourceProvider { "aws_main_route_table_association": resourceAwsMainRouteTableAssociation(), "aws_network_acl": resourceAwsNetworkAcl(), "aws_network_interface": resourceAwsNetworkInterface(), + "aws_opsworks_stack": resourceAwsOpsworksStack(), + "aws_opsworks_java_app_layer": resourceAwsOpsworksJavaAppLayer(), + "aws_opsworks_haproxy_layer": resourceAwsOpsworksHaproxyLayer(), + "aws_opsworks_static_web_layer": resourceAwsOpsworksStaticWebLayer(), + "aws_opsworks_php_app_layer": resourceAwsOpsworksPhpAppLayer(), + "aws_opsworks_rails_app_layer": resourceAwsOpsworksRailsAppLayer(), + "aws_opsworks_nodejs_app_layer": resourceAwsOpsworksNodejsAppLayer(), + "aws_opsworks_memcached_layer": resourceAwsOpsworksMemcachedLayer(), + "aws_opsworks_mysql_layer": resourceAwsOpsworksMysqlLayer(), + "aws_opsworks_ganglia_layer": resourceAwsOpsworksGangliaLayer(), + "aws_opsworks_custom_layer": resourceAwsOpsworksCustomLayer(), "aws_proxy_protocol_policy": resourceAwsProxyProtocolPolicy(), "aws_route53_delegation_set": resourceAwsRoute53DelegationSet(), "aws_route53_record": resourceAwsRoute53Record(), diff --git a/builtin/providers/aws/resource_aws_opsworks_custom_layer.go b/builtin/providers/aws/resource_aws_opsworks_custom_layer.go new file mode 100644 index 0000000000..59de60db6a --- /dev/null +++ b/builtin/providers/aws/resource_aws_opsworks_custom_layer.go @@ -0,0 +1,17 @@ +package aws + +import ( + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsOpsworksCustomLayer() *schema.Resource { + layerType := &opsworksLayerType{ + TypeName: "custom", + CustomShortName: true, + + // The "custom" layer type has no additional attributes + Attributes: map[string]*opsworksLayerTypeAttribute{}, + } + + return layerType.SchemaResource() +} diff --git a/builtin/providers/aws/resource_aws_opsworks_custom_layer_test.go b/builtin/providers/aws/resource_aws_opsworks_custom_layer_test.go new file mode 100644 index 0000000000..14a65b1061 --- /dev/null +++ b/builtin/providers/aws/resource_aws_opsworks_custom_layer_test.go @@ -0,0 +1,234 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +// These tests assume the existence of predefined Opsworks IAM roles named `aws-opsworks-ec2-role` +// and `aws-opsworks-service-role`. + +func TestAccAwsOpsworksCustomLayer(t *testing.T) { + opsiam := testAccAwsOpsworksStackIam{} + testAccAwsOpsworksStackPopulateIam(t, &opsiam) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsOpsworksCustomLayerDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: fmt.Sprintf(testAccAwsOpsworksCustomLayerConfigCreate, opsiam.ServiceRoleArn, opsiam.InstanceProfileArn), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "name", "tf-ops-acc-custom-layer", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "auto_assign_elastic_ips", "false", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "auto_healing", "true", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "drain_elb_on_shutdown", "true", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "instance_shutdown_timeout", "300", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "custom_security_group_ids.#", "2", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "system_packages.#", "2", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "system_packages.1368285564", "git", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "system_packages.2937857443", "golang", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "ebs_volume.#", "1", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "ebs_volume.3575749636.type", "gp2", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "ebs_volume.3575749636.number_of_disks", "2", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "ebs_volume.3575749636.mount_point", "/home", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "ebs_volume.3575749636.size", "100", + ), + ), + }, + resource.TestStep{ + Config: fmt.Sprintf(testAccAwsOpsworksCustomLayerConfigUpdate, opsiam.ServiceRoleArn, opsiam.InstanceProfileArn), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "name", "tf-ops-acc-custom-layer", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "drain_elb_on_shutdown", "false", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "instance_shutdown_timeout", "120", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "custom_security_group_ids.#", "3", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "system_packages.#", "3", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "system_packages.1368285564", "git", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "system_packages.2937857443", "golang", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "system_packages.4101929740", "subversion", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "ebs_volume.#", "2", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "ebs_volume.3575749636.type", "gp2", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "ebs_volume.3575749636.number_of_disks", "2", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "ebs_volume.3575749636.mount_point", "/home", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "ebs_volume.3575749636.size", "100", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "ebs_volume.1266957920.type", "io1", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "ebs_volume.1266957920.number_of_disks", "4", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "ebs_volume.1266957920.mount_point", "/var", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "ebs_volume.1266957920.size", "100", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "ebs_volume.1266957920.raid_level", "1", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_custom_layer.tf-acc", "ebs_volume.1266957920.iops", "3000", + ), + ), + }, + }, + }) +} + +func testAccCheckAwsOpsworksCustomLayerDestroy(s *terraform.State) error { + if len(s.RootModule().Resources) > 0 { + return fmt.Errorf("Expected all resources to be gone, but found: %#v", s.RootModule().Resources) + } + + return nil +} + +var testAccAwsOpsworksCustomLayerSecurityGroups = ` +resource "aws_security_group" "tf-ops-acc-layer1" { + name = "tf-ops-acc-layer1" + ingress { + from_port = 8 + to_port = -1 + protocol = "icmp" + cidr_blocks = ["0.0.0.0/0"] + } +} +resource "aws_security_group" "tf-ops-acc-layer2" { + name = "tf-ops-acc-layer2" + ingress { + from_port = 8 + to_port = -1 + protocol = "icmp" + cidr_blocks = ["0.0.0.0/0"] + } +} +` + +var testAccAwsOpsworksCustomLayerConfigCreate = testAccAwsOpsworksStackConfigNoVpcCreate + testAccAwsOpsworksCustomLayerSecurityGroups + ` +resource "aws_opsworks_custom_layer" "tf-acc" { + stack_id = "${aws_opsworks_stack.tf-acc.id}" + name = "tf-ops-acc-custom-layer" + short_name = "tf-ops-acc-custom-layer" + auto_assign_public_ips = true + custom_security_group_ids = [ + "${aws_security_group.tf-ops-acc-layer1.id}", + "${aws_security_group.tf-ops-acc-layer2.id}", + ] + drain_elb_on_shutdown = true + instance_shutdown_timeout = 300 + system_packages = [ + "git", + "golang", + ] + ebs_volume { + type = "gp2" + number_of_disks = 2 + mount_point = "/home" + size = 100 + raid_level = 0 + } +} +` + +var testAccAwsOpsworksCustomLayerConfigUpdate = testAccAwsOpsworksStackConfigNoVpcCreate + testAccAwsOpsworksCustomLayerSecurityGroups + ` +resource "aws_security_group" "tf-ops-acc-layer3" { + name = "tf-ops-acc-layer3" + ingress { + from_port = 8 + to_port = -1 + protocol = "icmp" + cidr_blocks = ["0.0.0.0/0"] + } +} +resource "aws_opsworks_custom_layer" "tf-acc" { + stack_id = "${aws_opsworks_stack.tf-acc.id}" + name = "tf-ops-acc-custom-layer" + short_name = "tf-ops-acc-custom-layer" + auto_assign_public_ips = true + custom_security_group_ids = [ + "${aws_security_group.tf-ops-acc-layer1.id}", + "${aws_security_group.tf-ops-acc-layer2.id}", + "${aws_security_group.tf-ops-acc-layer3.id}", + ] + drain_elb_on_shutdown = false + instance_shutdown_timeout = 120 + system_packages = [ + "git", + "golang", + "subversion", + ] + ebs_volume { + type = "gp2" + number_of_disks = 2 + mount_point = "/home" + size = 100 + raid_level = 0 + } + ebs_volume { + type = "io1" + number_of_disks = 4 + mount_point = "/var" + size = 100 + raid_level = 1 + iops = 3000 + } +} +` diff --git a/builtin/providers/aws/resource_aws_opsworks_ganglia_layer.go b/builtin/providers/aws/resource_aws_opsworks_ganglia_layer.go new file mode 100644 index 0000000000..c37bb70e5d --- /dev/null +++ b/builtin/providers/aws/resource_aws_opsworks_ganglia_layer.go @@ -0,0 +1,33 @@ +package aws + +import ( + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsOpsworksGangliaLayer() *schema.Resource { + layerType := &opsworksLayerType{ + TypeName: "monitoring-master", + DefaultLayerName: "Ganglia", + + Attributes: map[string]*opsworksLayerTypeAttribute{ + "url": &opsworksLayerTypeAttribute{ + AttrName: "GangliaUrl", + Type: schema.TypeString, + Default: "/ganglia", + }, + "username": &opsworksLayerTypeAttribute{ + AttrName: "GangliaUser", + Type: schema.TypeString, + Default: "opsworks", + }, + "password": &opsworksLayerTypeAttribute{ + AttrName: "GangliaPassword", + Type: schema.TypeString, + Required: true, + WriteOnly: true, + }, + }, + } + + return layerType.SchemaResource() +} diff --git a/builtin/providers/aws/resource_aws_opsworks_haproxy_layer.go b/builtin/providers/aws/resource_aws_opsworks_haproxy_layer.go new file mode 100644 index 0000000000..2b05dce05b --- /dev/null +++ b/builtin/providers/aws/resource_aws_opsworks_haproxy_layer.go @@ -0,0 +1,48 @@ +package aws + +import ( + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsOpsworksHaproxyLayer() *schema.Resource { + layerType := &opsworksLayerType{ + TypeName: "lb", + DefaultLayerName: "HAProxy", + + Attributes: map[string]*opsworksLayerTypeAttribute{ + "stats_enabled": &opsworksLayerTypeAttribute{ + AttrName: "EnableHaproxyStats", + Type: schema.TypeBool, + Default: true, + }, + "stats_url": &opsworksLayerTypeAttribute{ + AttrName: "HaproxyStatsUrl", + Type: schema.TypeString, + Default: "/haproxy?stats", + }, + "stats_user": &opsworksLayerTypeAttribute{ + AttrName: "HaproxyStatsUser", + Type: schema.TypeString, + Default: "opsworks", + }, + "stats_password": &opsworksLayerTypeAttribute{ + AttrName: "HaproxyStatsPassword", + Type: schema.TypeString, + WriteOnly: true, + Required: true, + }, + "healthcheck_url": &opsworksLayerTypeAttribute{ + AttrName: "HaproxyHealthCheckUrl", + Type: schema.TypeString, + Default: "/", + }, + "healthcheck_method": &opsworksLayerTypeAttribute{ + AttrName: "HaproxyHealthCheckMethod", + Type: schema.TypeString, + Default: "OPTIONS", + }, + }, + } + + return layerType.SchemaResource() +} diff --git a/builtin/providers/aws/resource_aws_opsworks_java_app_layer.go b/builtin/providers/aws/resource_aws_opsworks_java_app_layer.go new file mode 100644 index 0000000000..2b79fcfad3 --- /dev/null +++ b/builtin/providers/aws/resource_aws_opsworks_java_app_layer.go @@ -0,0 +1,42 @@ +package aws + +import ( + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsOpsworksJavaAppLayer() *schema.Resource { + layerType := &opsworksLayerType{ + TypeName: "java-app", + DefaultLayerName: "Java App Server", + + Attributes: map[string]*opsworksLayerTypeAttribute{ + "jvm_type": &opsworksLayerTypeAttribute{ + AttrName: "Jvm", + Type: schema.TypeString, + Default: "openjdk", + }, + "jvm_version": &opsworksLayerTypeAttribute{ + AttrName: "JvmVersion", + Type: schema.TypeString, + Default: "7", + }, + "jvm_options": &opsworksLayerTypeAttribute{ + AttrName: "JvmOptions", + Type: schema.TypeString, + Default: "", + }, + "app_server": &opsworksLayerTypeAttribute{ + AttrName: "JavaAppServer", + Type: schema.TypeString, + Default: "tomcat", + }, + "app_server_version": &opsworksLayerTypeAttribute{ + AttrName: "JavaAppServerVersion", + Type: schema.TypeString, + Default: "7", + }, + }, + } + + return layerType.SchemaResource() +} diff --git a/builtin/providers/aws/resource_aws_opsworks_memcached_layer.go b/builtin/providers/aws/resource_aws_opsworks_memcached_layer.go new file mode 100644 index 0000000000..626b428bb5 --- /dev/null +++ b/builtin/providers/aws/resource_aws_opsworks_memcached_layer.go @@ -0,0 +1,22 @@ +package aws + +import ( + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsOpsworksMemcachedLayer() *schema.Resource { + layerType := &opsworksLayerType{ + TypeName: "memcached", + DefaultLayerName: "Memcached", + + Attributes: map[string]*opsworksLayerTypeAttribute{ + "allocated_memory": &opsworksLayerTypeAttribute{ + AttrName: "MemcachedMemory", + Type: schema.TypeInt, + Default: 512, + }, + }, + } + + return layerType.SchemaResource() +} diff --git a/builtin/providers/aws/resource_aws_opsworks_mysql_layer.go b/builtin/providers/aws/resource_aws_opsworks_mysql_layer.go new file mode 100644 index 0000000000..6ab4476a3d --- /dev/null +++ b/builtin/providers/aws/resource_aws_opsworks_mysql_layer.go @@ -0,0 +1,27 @@ +package aws + +import ( + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsOpsworksMysqlLayer() *schema.Resource { + layerType := &opsworksLayerType{ + TypeName: "db-master", + DefaultLayerName: "MySQL", + + Attributes: map[string]*opsworksLayerTypeAttribute{ + "root_password": &opsworksLayerTypeAttribute{ + AttrName: "MysqlRootPassword", + Type: schema.TypeString, + WriteOnly: true, + }, + "root_password_on_all_instances": &opsworksLayerTypeAttribute{ + AttrName: "MysqlRootPasswordUbiquitous", + Type: schema.TypeBool, + Default: true, + }, + }, + } + + return layerType.SchemaResource() +} diff --git a/builtin/providers/aws/resource_aws_opsworks_nodejs_app_layer.go b/builtin/providers/aws/resource_aws_opsworks_nodejs_app_layer.go new file mode 100644 index 0000000000..24f3d0f3eb --- /dev/null +++ b/builtin/providers/aws/resource_aws_opsworks_nodejs_app_layer.go @@ -0,0 +1,22 @@ +package aws + +import ( + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsOpsworksNodejsAppLayer() *schema.Resource { + layerType := &opsworksLayerType{ + TypeName: "nodejs-app", + DefaultLayerName: "Node.js App Server", + + Attributes: map[string]*opsworksLayerTypeAttribute{ + "nodejs_version": &opsworksLayerTypeAttribute{ + AttrName: "NodejsVersion", + Type: schema.TypeString, + Default: "0.10.38", + }, + }, + } + + return layerType.SchemaResource() +} diff --git a/builtin/providers/aws/resource_aws_opsworks_php_app_layer.go b/builtin/providers/aws/resource_aws_opsworks_php_app_layer.go new file mode 100644 index 0000000000..c3176af5bd --- /dev/null +++ b/builtin/providers/aws/resource_aws_opsworks_php_app_layer.go @@ -0,0 +1,16 @@ +package aws + +import ( + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsOpsworksPhpAppLayer() *schema.Resource { + layerType := &opsworksLayerType{ + TypeName: "php-app", + DefaultLayerName: "PHP App Server", + + Attributes: map[string]*opsworksLayerTypeAttribute{}, + } + + return layerType.SchemaResource() +} diff --git a/builtin/providers/aws/resource_aws_opsworks_rails_app_layer.go b/builtin/providers/aws/resource_aws_opsworks_rails_app_layer.go new file mode 100644 index 0000000000..54a0084ddb --- /dev/null +++ b/builtin/providers/aws/resource_aws_opsworks_rails_app_layer.go @@ -0,0 +1,47 @@ +package aws + +import ( + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsOpsworksRailsAppLayer() *schema.Resource { + layerType := &opsworksLayerType{ + TypeName: "rails-app", + DefaultLayerName: "Rails App Server", + + Attributes: map[string]*opsworksLayerTypeAttribute{ + "ruby_version": &opsworksLayerTypeAttribute{ + AttrName: "RubyVersion", + Type: schema.TypeString, + Default: "2.0.0", + }, + "app_server": &opsworksLayerTypeAttribute{ + AttrName: "RailsStack", + Type: schema.TypeString, + Default: "apache_passenger", + }, + "passenger_version": &opsworksLayerTypeAttribute{ + AttrName: "PassengerVersion", + Type: schema.TypeString, + Default: "4.0.46", + }, + "rubygems_version": &opsworksLayerTypeAttribute{ + AttrName: "RubygemsVersion", + Type: schema.TypeString, + Default: "2.2.2", + }, + "manage_bundler": &opsworksLayerTypeAttribute{ + AttrName: "ManageBundler", + Type: schema.TypeBool, + Default: true, + }, + "bundler_version": &opsworksLayerTypeAttribute{ + AttrName: "BundlerVersion", + Type: schema.TypeString, + Default: "1.5.3", + }, + }, + } + + return layerType.SchemaResource() +} diff --git a/builtin/providers/aws/resource_aws_opsworks_stack.go b/builtin/providers/aws/resource_aws_opsworks_stack.go new file mode 100644 index 0000000000..5d0bf1aa83 --- /dev/null +++ b/builtin/providers/aws/resource_aws_opsworks_stack.go @@ -0,0 +1,456 @@ +package aws + +import ( + "fmt" + "log" + "strings" + "time" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/opsworks" +) + +func resourceAwsOpsworksStack() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsOpsworksStackCreate, + Read: resourceAwsOpsworksStackRead, + Update: resourceAwsOpsworksStackUpdate, + Delete: resourceAwsOpsworksStackDelete, + + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + + "region": &schema.Schema{ + Type: schema.TypeString, + ForceNew: true, + Required: true, + }, + + "service_role_arn": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + + "default_instance_profile_arn": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + + "color": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + + "configuration_manager_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "Chef", + }, + + "configuration_manager_version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "11.4", + }, + + "manage_berkshelf": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + + "berkshelf_version": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "3.2.0", + }, + + "custom_cookbooks_source": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + + "url": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + + "username": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + + "password": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + + "revision": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + + "ssh_key": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + + "custom_json": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + + "default_availability_zone": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "default_os": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "Ubuntu 12.04 LTS", + }, + + "default_root_device_type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "instance-store", + }, + + "default_ssh_key_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + + "default_subnet_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + + "hostname_theme": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "Layer_Dependent", + }, + + "use_custom_cookbooks": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + + "use_opsworks_security_groups": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + + "vpc_id": &schema.Schema{ + Type: schema.TypeString, + ForceNew: true, + Optional: true, + }, + }, + } +} + +func resourceAwsOpsworksStackValidate(d *schema.ResourceData) error { + cookbooksSourceCount := d.Get("custom_cookbooks_source.#").(int) + if cookbooksSourceCount > 1 { + return fmt.Errorf("Only one custom_cookbooks_source is permitted") + } + + vpcId := d.Get("vpc_id").(string) + if vpcId != "" { + if d.Get("default_subnet_id").(string) == "" { + return fmt.Errorf("default_subnet_id must be set if vpc_id is set") + } + } else { + if d.Get("default_availability_zone").(string) == "" { + return fmt.Errorf("either vpc_id or default_availability_zone must be set") + } + } + + return nil +} + +func resourceAwsOpsworksStackCustomCookbooksSource(d *schema.ResourceData) *opsworks.Source { + count := d.Get("custom_cookbooks_source.#").(int) + if count == 0 { + return nil + } + + return &opsworks.Source{ + Type: aws.String(d.Get("custom_cookbooks_source.0.type").(string)), + Url: aws.String(d.Get("custom_cookbooks_source.0.url").(string)), + Username: aws.String(d.Get("custom_cookbooks_source.0.username").(string)), + Password: aws.String(d.Get("custom_cookbooks_source.0.password").(string)), + Revision: aws.String(d.Get("custom_cookbooks_source.0.revision").(string)), + SshKey: aws.String(d.Get("custom_cookbooks_source.0.ssh_key").(string)), + } +} + +func resourceAwsOpsworksSetStackCustomCookbooksSource(d *schema.ResourceData, v *opsworks.Source) { + nv := make([]interface{}, 0, 1) + if v != nil { + m := make(map[string]interface{}) + if v.Type != nil { + m["type"] = *v.Type + } + if v.Url != nil { + m["url"] = *v.Url + } + if v.Username != nil { + m["username"] = *v.Username + } + if v.Password != nil { + m["password"] = *v.Password + } + if v.Revision != nil { + m["revision"] = *v.Revision + } + if v.SshKey != nil { + m["ssh_key"] = *v.SshKey + } + nv = append(nv, m) + } + + err := d.Set("custom_cookbooks_source", nv) + if err != nil { + // should never happen + panic(err) + } +} + +func resourceAwsOpsworksStackRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*AWSClient).opsworksconn + + req := &opsworks.DescribeStacksInput{ + StackIds: []*string{ + aws.String(d.Id()), + }, + } + + log.Printf("[DEBUG] Reading OpsWorks stack: %s", d.Id()) + + resp, err := client.DescribeStacks(req) + if err != nil { + if awserr, ok := err.(awserr.Error); ok { + if awserr.Code() == "ResourceNotFoundException" { + d.SetId("") + return nil + } + } + return err + } + + stack := resp.Stacks[0] + d.Set("name", stack.Name) + d.Set("region", stack.Region) + d.Set("default_instance_profile_arn", stack.DefaultInstanceProfileArn) + d.Set("service_role_arn", stack.ServiceRoleArn) + d.Set("default_availability_zone", stack.DefaultAvailabilityZone) + d.Set("default_os", stack.DefaultOs) + d.Set("default_root_device_type", stack.DefaultRootDeviceType) + d.Set("default_ssh_key_name", stack.DefaultSshKeyName) + d.Set("default_subnet_id", stack.DefaultSubnetId) + d.Set("hostname_theme", stack.HostnameTheme) + d.Set("use_custom_cookbooks", stack.UseCustomCookbooks) + d.Set("use_opsworks_security_groups", stack.UseOpsworksSecurityGroups) + d.Set("vpc_id", stack.VpcId) + if color, ok := stack.Attributes["Color"]; ok { + d.Set("color", color) + } + if stack.ConfigurationManager != nil { + d.Set("configuration_manager_name", stack.ConfigurationManager.Name) + d.Set("configuration_manager_version", stack.ConfigurationManager.Version) + } + if stack.ChefConfiguration != nil { + d.Set("berkshelf_version", stack.ChefConfiguration.BerkshelfVersion) + d.Set("manage_berkshelf", stack.ChefConfiguration.ManageBerkshelf) + } + resourceAwsOpsworksSetStackCustomCookbooksSource(d, stack.CustomCookbooksSource) + + return nil +} + +func resourceAwsOpsworksStackCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*AWSClient).opsworksconn + + err := resourceAwsOpsworksStackValidate(d) + if err != nil { + return err + } + + req := &opsworks.CreateStackInput{ + DefaultInstanceProfileArn: aws.String(d.Get("default_instance_profile_arn").(string)), + Name: aws.String(d.Get("name").(string)), + Region: aws.String(d.Get("region").(string)), + ServiceRoleArn: aws.String(d.Get("service_role_arn").(string)), + } + inVpc := false + if vpcId, ok := d.GetOk("vpc_id"); ok { + req.VpcId = aws.String(vpcId.(string)) + inVpc = true + } + if defaultSubnetId, ok := d.GetOk("default_subnet_id"); ok { + req.DefaultSubnetId = aws.String(defaultSubnetId.(string)) + } + if defaultAvailabilityZone, ok := d.GetOk("default_availability_zone"); ok { + req.DefaultAvailabilityZone = aws.String(defaultAvailabilityZone.(string)) + } + + log.Printf("[DEBUG] Creating OpsWorks stack: %s", *req.Name) + + var resp *opsworks.CreateStackOutput + err = resource.Retry(20*time.Minute, func() error { + var cerr error + resp, cerr = client.CreateStack(req) + if cerr != nil { + if opserr, ok := cerr.(awserr.Error); ok { + // If Terraform is also managing the service IAM role, + // it may have just been created and not yet be + // propagated. + // AWS doesn't provide a machine-readable code for this + // specific error, so we're forced to do fragile message + // matching. + // The full error we're looking for looks something like + // the following: + // Service Role Arn: [...] is not yet propagated, please try again in a couple of minutes + if opserr.Code() == "ValidationException" && strings.Contains(opserr.Message(), "not yet propagated") { + log.Printf("[INFO] Waiting for service IAM role to propagate") + return cerr + } + } + return resource.RetryError{Err: cerr} + } + return nil + }) + if err != nil { + return err + } + + stackId := *resp.StackId + d.SetId(stackId) + d.Set("id", stackId) + + if inVpc { + // For VPC-based stacks, OpsWorks asynchronously creates some default + // security groups which must exist before layers can be created. + // Unfortunately it doesn't tell us what the ids of these are, so + // we can't actually check for them. Instead, we just wait a nominal + // amount of time for their creation to complete. + log.Print("[INFO] Waiting for OpsWorks built-in security groups to be created") + time.Sleep(30 * time.Second) + } + + return resourceAwsOpsworksStackUpdate(d, meta) +} + +func resourceAwsOpsworksStackUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*AWSClient).opsworksconn + + err := resourceAwsOpsworksStackValidate(d) + if err != nil { + return err + } + + req := &opsworks.UpdateStackInput{ + CustomJson: aws.String(d.Get("custom_json").(string)), + DefaultInstanceProfileArn: aws.String(d.Get("default_instance_profile_arn").(string)), + DefaultRootDeviceType: aws.String(d.Get("default_root_device_type").(string)), + DefaultSshKeyName: aws.String(d.Get("default_ssh_key_name").(string)), + Name: aws.String(d.Get("name").(string)), + ServiceRoleArn: aws.String(d.Get("service_role_arn").(string)), + StackId: aws.String(d.Id()), + UseCustomCookbooks: aws.Bool(d.Get("use_custom_cookbooks").(bool)), + UseOpsworksSecurityGroups: aws.Bool(d.Get("use_opsworks_security_groups").(bool)), + Attributes: make(map[string]*string), + CustomCookbooksSource: resourceAwsOpsworksStackCustomCookbooksSource(d), + } + if v, ok := d.GetOk("default_os"); ok { + req.DefaultOs = aws.String(v.(string)) + } + if v, ok := d.GetOk("default_subnet_id"); ok { + req.DefaultSubnetId = aws.String(v.(string)) + } + if v, ok := d.GetOk("default_availability_zone"); ok { + req.DefaultAvailabilityZone = aws.String(v.(string)) + } + if v, ok := d.GetOk("hostname_theme"); ok { + req.HostnameTheme = aws.String(v.(string)) + } + if v, ok := d.GetOk("color"); ok { + req.Attributes["Color"] = aws.String(v.(string)) + } + req.ChefConfiguration = &opsworks.ChefConfiguration{ + BerkshelfVersion: aws.String(d.Get("berkshelf_version").(string)), + ManageBerkshelf: aws.Bool(d.Get("manage_berkshelf").(bool)), + } + req.ConfigurationManager = &opsworks.StackConfigurationManager{ + Name: aws.String(d.Get("configuration_manager_name").(string)), + Version: aws.String(d.Get("configuration_manager_version").(string)), + } + + log.Printf("[DEBUG] Updating OpsWorks stack: %s", d.Id()) + + _, err = client.UpdateStack(req) + if err != nil { + return err + } + + return resourceAwsOpsworksStackRead(d, meta) +} + +func resourceAwsOpsworksStackDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*AWSClient).opsworksconn + + req := &opsworks.DeleteStackInput{ + StackId: aws.String(d.Id()), + } + + log.Printf("[DEBUG] Deleting OpsWorks stack: %s", d.Id()) + + _, err := client.DeleteStack(req) + if err != nil { + return err + } + + // For a stack in a VPC, OpsWorks has created some default security groups + // in the VPC, which it will now delete. + // Unfortunately, the security groups are deleted asynchronously and there + // is no robust way for us to determine when it is done. The VPC itself + // isn't deletable until the security groups are cleaned up, so this could + // make 'terraform destroy' fail if the VPC is also managed and we don't + // wait for the security groups to be deleted. + // There is no robust way to check for this, so we'll just wait a + // nominal amount of time. + if _, ok := d.GetOk("vpc_id"); ok { + log.Print("[INFO] Waiting for Opsworks built-in security groups to be deleted") + time.Sleep(30 * time.Second) + } + + return nil +} diff --git a/builtin/providers/aws/resource_aws_opsworks_stack_test.go b/builtin/providers/aws/resource_aws_opsworks_stack_test.go new file mode 100644 index 0000000000..b740b6a20d --- /dev/null +++ b/builtin/providers/aws/resource_aws_opsworks_stack_test.go @@ -0,0 +1,353 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/iam" + "github.com/aws/aws-sdk-go/service/opsworks" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +// These tests assume the existence of predefined Opsworks IAM roles named `aws-opsworks-ec2-role` +// and `aws-opsworks-service-role`. + +/////////////////////////////// +//// Tests for the No-VPC case +/////////////////////////////// + +var testAccAwsOpsworksStackConfigNoVpcCreate = ` +resource "aws_opsworks_stack" "tf-acc" { + name = "tf-opsworks-acc" + region = "us-west-2" + service_role_arn = "%s" + default_instance_profile_arn = "%s" + default_availability_zone = "us-west-2a" + default_os = "Amazon Linux 2014.09" + default_root_device_type = "ebs" + custom_json = "{\"key\": \"value\"}" + configuration_manager_version = "11.10" + use_opsworks_security_groups = false +} +` +var testAccAWSOpsworksStackConfigNoVpcUpdate = ` +resource "aws_opsworks_stack" "tf-acc" { + name = "tf-opsworks-acc" + region = "us-west-2" + service_role_arn = "%s" + default_instance_profile_arn = "%s" + default_availability_zone = "us-west-2a" + default_os = "Amazon Linux 2014.09" + default_root_device_type = "ebs" + custom_json = "{\"key\": \"value\"}" + configuration_manager_version = "11.10" + use_opsworks_security_groups = false + use_custom_cookbooks = true + manage_berkshelf = true + custom_cookbooks_source { + type = "git" + revision = "master" + url = "https://github.com/awslabs/opsworks-example-cookbooks.git" + } +} +` + +func TestAccAwsOpsworksStackNoVpc(t *testing.T) { + opsiam := testAccAwsOpsworksStackIam{} + testAccAwsOpsworksStackPopulateIam(t, &opsiam) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsOpsworksStackDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: fmt.Sprintf(testAccAwsOpsworksStackConfigNoVpcCreate, opsiam.ServiceRoleArn, opsiam.InstanceProfileArn), + Check: testAccAwsOpsworksStackCheckResourceAttrsCreate, + }, + resource.TestStep{ + Config: fmt.Sprintf(testAccAWSOpsworksStackConfigNoVpcUpdate, opsiam.ServiceRoleArn, opsiam.InstanceProfileArn), + Check: testAccAwsOpsworksStackCheckResourceAttrsUpdate, + }, + }, + }) +} + +//////////////////////////// +//// Tests for the VPC case +//////////////////////////// + +var testAccAwsOpsworksStackConfigVpcCreate = ` +resource "aws_vpc" "tf-acc" { + cidr_block = "10.3.5.0/24" +} +resource "aws_subnet" "tf-acc" { + vpc_id = "${aws_vpc.tf-acc.id}" + cidr_block = "${aws_vpc.tf-acc.cidr_block}" + availability_zone = "us-west-2a" +} +resource "aws_opsworks_stack" "tf-acc" { + name = "tf-opsworks-acc" + region = "us-west-2" + vpc_id = "${aws_vpc.tf-acc.id}" + default_subnet_id = "${aws_subnet.tf-acc.id}" + service_role_arn = "%s" + default_instance_profile_arn = "%s" + default_os = "Amazon Linux 2014.09" + default_root_device_type = "ebs" + custom_json = "{\"key\": \"value\"}" + configuration_manager_version = "11.10" + use_opsworks_security_groups = false +} +` + +var testAccAWSOpsworksStackConfigVpcUpdate = ` +resource "aws_vpc" "tf-acc" { + cidr_block = "10.3.5.0/24" +} +resource "aws_subnet" "tf-acc" { + vpc_id = "${aws_vpc.tf-acc.id}" + cidr_block = "${aws_vpc.tf-acc.cidr_block}" + availability_zone = "us-west-2a" +} +resource "aws_opsworks_stack" "tf-acc" { + name = "tf-opsworks-acc" + region = "us-west-2" + vpc_id = "${aws_vpc.tf-acc.id}" + default_subnet_id = "${aws_subnet.tf-acc.id}" + service_role_arn = "%s" + default_instance_profile_arn = "%s" + default_os = "Amazon Linux 2014.09" + default_root_device_type = "ebs" + custom_json = "{\"key\": \"value\"}" + configuration_manager_version = "11.10" + use_opsworks_security_groups = false + use_custom_cookbooks = true + manage_berkshelf = true + custom_cookbooks_source { + type = "git" + revision = "master" + url = "https://github.com/awslabs/opsworks-example-cookbooks.git" + } +} +` + +func TestAccAwsOpsworksStackVpc(t *testing.T) { + opsiam := testAccAwsOpsworksStackIam{} + testAccAwsOpsworksStackPopulateIam(t, &opsiam) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsOpsworksStackDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: fmt.Sprintf(testAccAwsOpsworksStackConfigVpcCreate, opsiam.ServiceRoleArn, opsiam.InstanceProfileArn), + Check: testAccAwsOpsworksStackCheckResourceAttrsCreate, + }, + resource.TestStep{ + Config: fmt.Sprintf(testAccAWSOpsworksStackConfigVpcUpdate, opsiam.ServiceRoleArn, opsiam.InstanceProfileArn), + Check: resource.ComposeTestCheckFunc( + testAccAwsOpsworksStackCheckResourceAttrsUpdate, + testAccAwsOpsworksCheckVpc, + ), + }, + }, + }) +} + +//////////////////////////// +//// Checkers and Utilities +//////////////////////////// + +var testAccAwsOpsworksStackCheckResourceAttrsCreate = resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "aws_opsworks_stack.tf-acc", + "name", + "tf-opsworks-acc", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_stack.tf-acc", + "default_availability_zone", + "us-west-2a", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_stack.tf-acc", + "default_os", + "Amazon Linux 2014.09", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_stack.tf-acc", + "default_root_device_type", + "ebs", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_stack.tf-acc", + "custom_json", + `{"key": "value"}`, + ), + resource.TestCheckResourceAttr( + "aws_opsworks_stack.tf-acc", + "configuration_manager_version", + "11.10", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_stack.tf-acc", + "use_opsworks_security_groups", + "false", + ), +) + +var testAccAwsOpsworksStackCheckResourceAttrsUpdate = resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "aws_opsworks_stack.tf-acc", + "name", + "tf-opsworks-acc", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_stack.tf-acc", + "default_availability_zone", + "us-west-2a", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_stack.tf-acc", + "default_os", + "Amazon Linux 2014.09", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_stack.tf-acc", + "default_root_device_type", + "ebs", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_stack.tf-acc", + "custom_json", + `{"key": "value"}`, + ), + resource.TestCheckResourceAttr( + "aws_opsworks_stack.tf-acc", + "configuration_manager_version", + "11.10", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_stack.tf-acc", + "use_opsworks_security_groups", + "false", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_stack.tf-acc", + "use_custom_cookbooks", + "true", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_stack.tf-acc", + "manage_berkshelf", + "true", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_stack.tf-acc", + "custom_cookbooks_source.0.type", + "git", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_stack.tf-acc", + "custom_cookbooks_source.0.revision", + "master", + ), + resource.TestCheckResourceAttr( + "aws_opsworks_stack.tf-acc", + "custom_cookbooks_source.0.url", + "https://github.com/awslabs/opsworks-example-cookbooks.git", + ), +) + +func testAccAwsOpsworksCheckVpc(s *terraform.State) error { + rs, ok := s.RootModule().Resources["aws_opsworks_stack.tf-acc"] + if !ok { + return fmt.Errorf("Not found: %s", "aws_opsworks_stack.tf-acc") + } + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } + + p := rs.Primary + + opsworksconn := testAccProvider.Meta().(*AWSClient).opsworksconn + describeOpts := &opsworks.DescribeStacksInput{ + StackIds: []*string{aws.String(p.ID)}, + } + resp, err := opsworksconn.DescribeStacks(describeOpts) + if err != nil { + return err + } + if len(resp.Stacks) == 0 { + return fmt.Errorf("No stack %s not found", p.ID) + } + if p.Attributes["vpc_id"] != *resp.Stacks[0].VpcId { + return fmt.Errorf("VPCID Got %s, expected %s", *resp.Stacks[0].VpcId, p.Attributes["vpc_id"]) + } + if p.Attributes["default_subnet_id"] != *resp.Stacks[0].DefaultSubnetId { + return fmt.Errorf("VPCID Got %s, expected %s", *resp.Stacks[0].DefaultSubnetId, p.Attributes["default_subnet_id"]) + } + return nil +} + +func testAccCheckAwsOpsworksStackDestroy(s *terraform.State) error { + if len(s.RootModule().Resources) > 0 { + return fmt.Errorf("Expected all resources to be gone, but found: %#v", s.RootModule().Resources) + } + + return nil +} + +// Holds the two IAM object ARNs used in stack objects we'll create. +type testAccAwsOpsworksStackIam struct { + ServiceRoleArn string + InstanceProfileArn string +} + +func testAccAwsOpsworksStackPopulateIam(t *testing.T, opsiam *testAccAwsOpsworksStackIam) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccInstanceConfig_pre, // noop + Check: testAccCheckAwsOpsworksEnsureIam(t, opsiam), + }, + }, + }) +} + +func testAccCheckAwsOpsworksEnsureIam(t *testing.T, opsiam *testAccAwsOpsworksStackIam) func(*terraform.State) error { + return func(_ *terraform.State) error { + iamconn := testAccProvider.Meta().(*AWSClient).iamconn + + serviceRoleOpts := &iam.GetRoleInput{ + RoleName: aws.String("aws-opsworks-service-role"), + } + respServiceRole, err := iamconn.GetRole(serviceRoleOpts) + if err != nil { + return err + } + + instanceProfileOpts := &iam.GetInstanceProfileInput{ + InstanceProfileName: aws.String("aws-opsworks-ec2-role"), + } + respInstanceProfile, err := iamconn.GetInstanceProfile(instanceProfileOpts) + if err != nil { + return err + } + + opsiam.ServiceRoleArn = *respServiceRole.Role.Arn + opsiam.InstanceProfileArn = *respInstanceProfile.InstanceProfile.Arn + + t.Logf("[DEBUG] ServiceRoleARN for OpsWorks: %s", opsiam.ServiceRoleArn) + t.Logf("[DEBUG] Instance Profile ARN for OpsWorks: %s", opsiam.InstanceProfileArn) + + return nil + + } +} diff --git a/builtin/providers/aws/resource_aws_opsworks_static_web_layer.go b/builtin/providers/aws/resource_aws_opsworks_static_web_layer.go new file mode 100644 index 0000000000..df91b1b1b4 --- /dev/null +++ b/builtin/providers/aws/resource_aws_opsworks_static_web_layer.go @@ -0,0 +1,16 @@ +package aws + +import ( + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsOpsworksStaticWebLayer() *schema.Resource { + layerType := &opsworksLayerType{ + TypeName: "web", + DefaultLayerName: "Static Web Server", + + Attributes: map[string]*opsworksLayerTypeAttribute{}, + } + + return layerType.SchemaResource() +} diff --git a/website/source/docs/providers/aws/r/opsworks_custom_layer.html.markdown b/website/source/docs/providers/aws/r/opsworks_custom_layer.html.markdown new file mode 100644 index 0000000000..8bab636929 --- /dev/null +++ b/website/source/docs/providers/aws/r/opsworks_custom_layer.html.markdown @@ -0,0 +1,65 @@ +--- +layout: "aws" +page_title: "AWS: aws_opsworks_custom_layer" +sidebar_current: "docs-aws-resource-opsworks-custom-layer" +description: |- + Provides an OpsWorks custom layer resource. +--- + +# aws\_opsworks\_custom\_layer + +Provides an OpsWorks custom layer resource. + +## Example Usage + +``` +resource "aws_opsworks_custom_layer" "custlayer" { + name = "My Awesome Custom Layer" + short_name = "awesome" + stack_id = "${aws_opsworks_stack.main.id}" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) A human-readable name for the layer. +* `short_name` - (Required) A short, machine-readable name for the layer, which will be used to identify it in the Chef node JSON. +* `stack_id` - (Required) The id of the stack the layer will belong to. +* `auto_assign_elastic_ips` - (Optional) Whether to automatically assign an elastic IP address to the layer's instances. +* `auto_assign_public_ips` - (Optional) For stacks belonging to a VPC, whether to automatically assign a public IP address to each of the layer's instances. +* `custom_instance_profile_arn` - (Optional) The ARN of an IAM profile that will be used for the layer's instances. +* `custom_security_group_ids` - (Optional) Ids for a set of security groups to apply to the layer's instances. +* `auto_healing` - (Optional) Whether to enable auto-healing for the layer. +* `install_updates_on_boot` - (Optional) Whether to install OS and package updates on each instance when it boots. +* `instance_shutdown_timeout` - (Optional) The time, in seconds, that OpsWorks will wait for Chef to complete after triggering the Shutdown event. +* `drain_elb_on_shutdown` - (Optional) Whether to enable Elastic Load Balancing connection draining. +* `system_packages` - (Optional) Names of a set of system packages to install on the layer's instances. +* `use_ebs_optimized_instances` - (Optional) Whether to use EBS-optimized instances. +* `ebs_volume` - (Optional) `ebs_volume` blocks, as described below, will each create an EBS volume and connect it to the layer's instances. + +The following extra optional arguments, all lists of Chef recipe names, allow +custom Chef recipes to be applied to layer instances at the five different +lifecycle events, if custom cookbooks are enabled on the layer's stack: + +* `custom_configure_recipes` +* `custom_deploy_recipes` +* `custom_setup_recipes` +* `custom_shutdown_recipes` +* `custom_undeploy_recipes` + +An `ebs_volume` block supports the following arguments: + +* `mount_point` - (Required) The path to mount the EBS volume on the layer's instances. +* `size` - (Required) The size of the volume in gigabytes. +* `number_of_disks` - (Required) The number of disks to use for the EBS volume. +* `raid_level` - (Required) The RAID level to use for the volume. +* `type` - (Optional) The type of volume to create. This may be `standard` (the default), `io1` or `gp2`. +* `iops` - (Optional) For PIOPS volumes, the IOPS per disk. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The id of the layer. diff --git a/website/source/docs/providers/aws/r/opsworks_ganglia_layer.html.markdown b/website/source/docs/providers/aws/r/opsworks_ganglia_layer.html.markdown new file mode 100644 index 0000000000..2137e0bf2a --- /dev/null +++ b/website/source/docs/providers/aws/r/opsworks_ganglia_layer.html.markdown @@ -0,0 +1,66 @@ +--- +layout: "aws" +page_title: "AWS: aws_opsworks_ganglia_layer" +sidebar_current: "docs-aws-resource-opsworks-ganglia-layer" +description: |- + Provides an OpsWorks Ganglia layer resource. +--- + +# aws\_opsworks\_ganglia\_layer + +Provides an OpsWorks Ganglia layer resource. + +## Example Usage + +``` +resource "aws_opsworks_ganglia_layer" "monitor" { + stack_id = "${aws_opsworks_stack.main.id}" + password = "foobarbaz" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `stack_id` - (Required) The id of the stack the layer will belong to. +* `password` - (Required) The password to use for Ganglia. +* `name` - (Optional) A human-readable name for the layer. +* `auto_assign_elastic_ips` - (Optional) Whether to automatically assign an elastic IP address to the layer's instances. +* `auto_assign_public_ips` - (Optional) For stacks belonging to a VPC, whether to automatically assign a public IP address to each of the layer's instances. +* `custom_instance_profile_arn` - (Optional) The ARN of an IAM profile that will be used for the layer's instances. +* `custom_security_group_ids` - (Optional) Ids for a set of security groups to apply to the layer's instances. +* `auto_healing` - (Optional) Whether to enable auto-healing for the layer. +* `install_updates_on_boot` - (Optional) Whether to install OS and package updates on each instance when it boots. +* `instance_shutdown_timeout` - (Optional) The time, in seconds, that OpsWorks will wait for Chef to complete after triggering the Shutdown event. +* `drain_elb_on_shutdown` - (Optional) Whether to enable Elastic Load Balancing connection draining. +* `system_packages` - (Optional) Names of a set of system packages to install on the layer's instances. +* `url` - (Optional) The URL path to use for Ganglia. Defaults to "/ganglia". +* `username` - (Optiona) The username to use for Ganglia. Defaults to "opsworks". +* `use_ebs_optimized_instances` - (Optional) Whether to use EBS-optimized instances. +* `ebs_volume` - (Optional) `ebs_volume` blocks, as described below, will each create an EBS volume and connect it to the layer's instances. + +The following extra optional arguments, all lists of Chef recipe names, allow +custom Chef recipes to be applied to layer instances at the five different +lifecycle events, if custom cookbooks are enabled on the layer's stack: + +* `custom_configure_recipes` +* `custom_deploy_recipes` +* `custom_setup_recipes` +* `custom_shutdown_recipes` +* `custom_undeploy_recipes` + +An `ebs_volume` block supports the following arguments: + +* `mount_point` - (Required) The path to mount the EBS volume on the layer's instances. +* `size` - (Required) The size of the volume in gigabytes. +* `number_of_disks` - (Required) The number of disks to use for the EBS volume. +* `raid_level` - (Required) The RAID level to use for the volume. +* `type` - (Optional) The type of volume to create. This may be `standard` (the default), `io1` or `gp2`. +* `iops` - (Optional) For PIOPS volumes, the IOPS per disk. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The id of the layer. diff --git a/website/source/docs/providers/aws/r/opsworks_haproxy_layer.html.markdown b/website/source/docs/providers/aws/r/opsworks_haproxy_layer.html.markdown new file mode 100644 index 0000000000..a921a8135e --- /dev/null +++ b/website/source/docs/providers/aws/r/opsworks_haproxy_layer.html.markdown @@ -0,0 +1,69 @@ +--- +layout: "aws" +page_title: "AWS: aws_opsworks_haproxy_layer" +sidebar_current: "docs-aws-resource-opsworks-haproxy-layer" +description: |- + Provides an OpsWorks HAProxy layer resource. +--- + +# aws\_opsworks\_haproxy\_layer + +Provides an OpsWorks haproxy layer resource. + +## Example Usage + +``` +resource "aws_opsworks_haproxy_layer" "lb" { + stack_id = "${aws_opsworks_stack.main.id}" + stats_password = "foobarbaz" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `stack_id` - (Required) The id of the stack the layer will belong to. +* `stats_password` - (Required) The password to use for HAProxy stats. +* `name` - (Optional) A human-readable name for the layer. +* `auto_assign_elastic_ips` - (Optional) Whether to automatically assign an elastic IP address to the layer's instances. +* `auto_assign_public_ips` - (Optional) For stacks belonging to a VPC, whether to automatically assign a public IP address to each of the layer's instances. +* `custom_instance_profile_arn` - (Optional) The ARN of an IAM profile that will be used for the layer's instances. +* `custom_security_group_ids` - (Optional) Ids for a set of security groups to apply to the layer's instances. +* `auto_healing` - (Optional) Whether to enable auto-healing for the layer. +* `healthcheck_method` - (Optional) HTTP method to use for instance healthchecks. Defaults to "OPTIONS". +* `healthcheck_url` - (Optional) URL path to use for instance healthchecks. Defaults to "/". +* `install_updates_on_boot` - (Optional) Whether to install OS and package updates on each instance when it boots. +* `instance_shutdown_timeout` - (Optional) The time, in seconds, that OpsWorks will wait for Chef to complete after triggering the Shutdown event. +* `drain_elb_on_shutdown` - (Optional) Whether to enable Elastic Load Balancing connection draining. +* `stats_enabled` - (Optional) Whether to enable HAProxy stats. +* `stats_url` - (Optional) The HAProxy stats URL. Defaults to "/haproxy?stats". +* `stats_user` - (Optional) The username for HAProxy stats. Defaults to "opsworks". +* `system_packages` - (Optional) Names of a set of system packages to install on the layer's instances. +* `use_ebs_optimized_instances` - (Optional) Whether to use EBS-optimized instances. +* `ebs_volume` - (Optional) `ebs_volume` blocks, as described below, will each create an EBS volume and connect it to the layer's instances. + +The following extra optional arguments, all lists of Chef recipe names, allow +custom Chef recipes to be applied to layer instances at the five different +lifecycle events, if custom cookbooks are enabled on the layer's stack: + +* `custom_configure_recipes` +* `custom_deploy_recipes` +* `custom_setup_recipes` +* `custom_shutdown_recipes` +* `custom_undeploy_recipes` + +An `ebs_volume` block supports the following arguments: + +* `mount_point` - (Required) The path to mount the EBS volume on the layer's instances. +* `size` - (Required) The size of the volume in gigabytes. +* `number_of_disks` - (Required) The number of disks to use for the EBS volume. +* `raid_level` - (Required) The RAID level to use for the volume. +* `type` - (Optional) The type of volume to create. This may be `standard` (the default), `io1` or `gp2`. +* `iops` - (Optional) For PIOPS volumes, the IOPS per disk. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The id of the layer. diff --git a/website/source/docs/providers/aws/r/opsworks_java_app_layer.html.markdown b/website/source/docs/providers/aws/r/opsworks_java_app_layer.html.markdown new file mode 100644 index 0000000000..c9a4823fe3 --- /dev/null +++ b/website/source/docs/providers/aws/r/opsworks_java_app_layer.html.markdown @@ -0,0 +1,67 @@ +--- +layout: "aws" +page_title: "AWS: aws_opsworks_java_app_layer" +sidebar_current: "docs-aws-resource-opsworks-java-app-layer" +description: |- + Provides an OpsWorks Java application layer resource. +--- + +# aws\_opsworks\_java\_app\_layer + +Provides an OpsWorks Java application layer resource. + +## Example Usage + +``` +resource "aws_opsworks_java_app_layer" "app" { + stack_id = "${aws_opsworks_stack.main.id}" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `stack_id` - (Required) The id of the stack the layer will belong to. +* `name` - (Optional) A human-readable name for the layer. +* `app_server` - (Optional) Keyword for the application container to use. Defaults to "tomcat". +* `app_server_version` - (Optional) Version of the selected application container to use. Defaults to "7". +* `auto_assign_elastic_ips` - (Optional) Whether to automatically assign an elastic IP address to the layer's instances. +* `auto_assign_public_ips` - (Optional) For stacks belonging to a VPC, whether to automatically assign a public IP address to each of the layer's instances. +* `custom_instance_profile_arn` - (Optional) The ARN of an IAM profile that will be used for the layer's instances. +* `custom_security_group_ids` - (Optional) Ids for a set of security groups to apply to the layer's instances. +* `auto_healing` - (Optional) Whether to enable auto-healing for the layer. +* `install_updates_on_boot` - (Optional) Whether to install OS and package updates on each instance when it boots. +* `instance_shutdown_timeout` - (Optional) The time, in seconds, that OpsWorks will wait for Chef to complete after triggering the Shutdown event. +* `jvm_type` - (Optional) Keyword for the type of JVM to use. Defaults to `openjdk`. +* `jvm_options` - (Optional) Options to set for the JVM. +* `jvm_version` - (Optional) Version of JVM to use. Defaults to "7". +* `drain_elb_on_shutdown` - (Optional) Whether to enable Elastic Load Balancing connection draining. +* `system_packages` - (Optional) Names of a set of system packages to install on the layer's instances. +* `use_ebs_optimized_instances` - (Optional) Whether to use EBS-optimized instances. +* `ebs_volume` - (Optional) `ebs_volume` blocks, as described below, will each create an EBS volume and connect it to the layer's instances. + +The following extra optional arguments, all lists of Chef recipe names, allow +custom Chef recipes to be applied to layer instances at the five different +lifecycle events, if custom cookbooks are enabled on the layer's stack: + +* `custom_configure_recipes` +* `custom_deploy_recipes` +* `custom_setup_recipes` +* `custom_shutdown_recipes` +* `custom_undeploy_recipes` + +An `ebs_volume` block supports the following arguments: + +* `mount_point` - (Required) The path to mount the EBS volume on the layer's instances. +* `size` - (Required) The size of the volume in gigabytes. +* `number_of_disks` - (Required) The number of disks to use for the EBS volume. +* `raid_level` - (Required) The RAID level to use for the volume. +* `type` - (Optional) The type of volume to create. This may be `standard` (the default), `io1` or `gp2`. +* `iops` - (Optional) For PIOPS volumes, the IOPS per disk. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The id of the layer. diff --git a/website/source/docs/providers/aws/r/opsworks_memcached_layer.html.markdown b/website/source/docs/providers/aws/r/opsworks_memcached_layer.html.markdown new file mode 100644 index 0000000000..4a725bd7cf --- /dev/null +++ b/website/source/docs/providers/aws/r/opsworks_memcached_layer.html.markdown @@ -0,0 +1,63 @@ +--- +layout: "aws" +page_title: "AWS: aws_opsworks_memcached_layer" +sidebar_current: "docs-aws-resource-opsworks-memcached-layer" +description: |- + Provides an OpsWorks memcached layer resource. +--- + +# aws\_opsworks\_memcached\_layer + +Provides an OpsWorks memcached layer resource. + +## Example Usage + +``` +resource "aws_opsworks_memcached_layer" "cache" { + stack_id = "${aws_opsworks_stack.main.id}" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `stack_id` - (Required) The id of the stack the layer will belong to. +* `name` - (Optional) A human-readable name for the layer. +* `allocated_memory` - (Optional) Amount of memory to allocate for the cache on each instance, in megabytes. Defaults to 512MB. +* `auto_assign_elastic_ips` - (Optional) Whether to automatically assign an elastic IP address to the layer's instances. +* `auto_assign_public_ips` - (Optional) For stacks belonging to a VPC, whether to automatically assign a public IP address to each of the layer's instances. +* `custom_instance_profile_arn` - (Optional) The ARN of an IAM profile that will be used for the layer's instances. +* `custom_security_group_ids` - (Optional) Ids for a set of security groups to apply to the layer's instances. +* `auto_healing` - (Optional) Whether to enable auto-healing for the layer. +* `install_updates_on_boot` - (Optional) Whether to install OS and package updates on each instance when it boots. +* `instance_shutdown_timeout` - (Optional) The time, in seconds, that OpsWorks will wait for Chef to complete after triggering the Shutdown event. +* `drain_elb_on_shutdown` - (Optional) Whether to enable Elastic Load Balancing connection draining. +* `system_packages` - (Optional) Names of a set of system packages to install on the layer's instances. +* `use_ebs_optimized_instances` - (Optional) Whether to use EBS-optimized instances. +* `ebs_volume` - (Optional) `ebs_volume` blocks, as described below, will each create an EBS volume and connect it to the layer's instances. + +The following extra optional arguments, all lists of Chef recipe names, allow +custom Chef recipes to be applied to layer instances at the five different +lifecycle events, if custom cookbooks are enabled on the layer's stack: + +* `custom_configure_recipes` +* `custom_deploy_recipes` +* `custom_setup_recipes` +* `custom_shutdown_recipes` +* `custom_undeploy_recipes` + +An `ebs_volume` block supports the following arguments: + +* `mount_point` - (Required) The path to mount the EBS volume on the layer's instances. +* `size` - (Required) The size of the volume in gigabytes. +* `number_of_disks` - (Required) The number of disks to use for the EBS volume. +* `raid_level` - (Required) The RAID level to use for the volume. +* `type` - (Optional) The type of volume to create. This may be `standard` (the default), `io1` or `gp2`. +* `iops` - (Optional) For PIOPS volumes, the IOPS per disk. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The id of the layer. diff --git a/website/source/docs/providers/aws/r/opsworks_mysql_layer.html.markdown b/website/source/docs/providers/aws/r/opsworks_mysql_layer.html.markdown new file mode 100644 index 0000000000..fcbcef97d5 --- /dev/null +++ b/website/source/docs/providers/aws/r/opsworks_mysql_layer.html.markdown @@ -0,0 +1,64 @@ +--- +layout: "aws" +page_title: "AWS: aws_opsworks_mysql_layer" +sidebar_current: "docs-aws-resource-opsworks-mysql-layer" +description: |- + Provides an OpsWorks MySQL layer resource. +--- + +# aws\_opsworks\_mysql\_layer + +Provides an OpsWorks MySQL layer resource. + +## Example Usage + +``` +resource "aws_opsworks_mysql_layer" "db" { + stack_id = "${aws_opsworks_stack.main.id}" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `stack_id` - (Required) The id of the stack the layer will belong to. +* `name` - (Optional) A human-readable name for the layer. +* `auto_assign_elastic_ips` - (Optional) Whether to automatically assign an elastic IP address to the layer's instances. +* `auto_assign_public_ips` - (Optional) For stacks belonging to a VPC, whether to automatically assign a public IP address to each of the layer's instances. +* `custom_instance_profile_arn` - (Optional) The ARN of an IAM profile that will be used for the layer's instances. +* `custom_security_group_ids` - (Optional) Ids for a set of security groups to apply to the layer's instances. +* `auto_healing` - (Optional) Whether to enable auto-healing for the layer. +* `install_updates_on_boot` - (Optional) Whether to install OS and package updates on each instance when it boots. +* `instance_shutdown_timeout` - (Optional) The time, in seconds, that OpsWorks will wait for Chef to complete after triggering the Shutdown event. +* `drain_elb_on_shutdown` - (Optional) Whether to enable Elastic Load Balancing connection draining. +* `root_password` - (Optional) Root password to use for MySQL. +* `root_password_on_all_instances` - (Optional) Whether to set the root user password to all instances in the stack so they can access the instances in this layer. +* `system_packages` - (Optional) Names of a set of system packages to install on the layer's instances. +* `use_ebs_optimized_instances` - (Optional) Whether to use EBS-optimized instances. +* `ebs_volume` - (Optional) `ebs_volume` blocks, as described below, will each create an EBS volume and connect it to the layer's instances. + +The following extra optional arguments, all lists of Chef recipe names, allow +custom Chef recipes to be applied to layer instances at the five different +lifecycle events, if custom cookbooks are enabled on the layer's stack: + +* `custom_configure_recipes` +* `custom_deploy_recipes` +* `custom_setup_recipes` +* `custom_shutdown_recipes` +* `custom_undeploy_recipes` + +An `ebs_volume` block supports the following arguments: + +* `mount_point` - (Required) The path to mount the EBS volume on the layer's instances. +* `size` - (Required) The size of the volume in gigabytes. +* `number_of_disks` - (Required) The number of disks to use for the EBS volume. +* `raid_level` - (Required) The RAID level to use for the volume. +* `type` - (Optional) The type of volume to create. This may be `standard` (the default), `io1` or `gp2`. +* `iops` - (Optional) For PIOPS volumes, the IOPS per disk. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The id of the layer. diff --git a/website/source/docs/providers/aws/r/opsworks_nodejs_app_layer.html.markdown b/website/source/docs/providers/aws/r/opsworks_nodejs_app_layer.html.markdown new file mode 100644 index 0000000000..e5a0f5b8a2 --- /dev/null +++ b/website/source/docs/providers/aws/r/opsworks_nodejs_app_layer.html.markdown @@ -0,0 +1,63 @@ +--- +layout: "aws" +page_title: "AWS: aws_opsworks_nodejs_app_layer" +sidebar_current: "docs-aws-resource-opsworks-nodejs-app-layer" +description: |- + Provides an OpsWorks NodeJS application layer resource. +--- + +# aws\_opsworks\_nodejs\_app\_layer + +Provides an OpsWorks NodeJS application layer resource. + +## Example Usage + +``` +resource "aws_opsworks_nodejs_app_layer" "app" { + stack_id = "${aws_opsworks_stack.main.id}" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `stack_id` - (Required) The id of the stack the layer will belong to. +* `name` - (Optional) A human-readable name for the layer. +* `auto_assign_elastic_ips` - (Optional) Whether to automatically assign an elastic IP address to the layer's instances. +* `auto_assign_public_ips` - (Optional) For stacks belonging to a VPC, whether to automatically assign a public IP address to each of the layer's instances. +* `custom_instance_profile_arn` - (Optional) The ARN of an IAM profile that will be used for the layer's instances. +* `custom_security_group_ids` - (Optional) Ids for a set of security groups to apply to the layer's instances. +* `auto_healing` - (Optional) Whether to enable auto-healing for the layer. +* `install_updates_on_boot` - (Optional) Whether to install OS and package updates on each instance when it boots. +* `instance_shutdown_timeout` - (Optional) The time, in seconds, that OpsWorks will wait for Chef to complete after triggering the Shutdown event. +* `drain_elb_on_shutdown` - (Optional) Whether to enable Elastic Load Balancing connection draining. +* `nodejs_version` - (Optional) The version of NodeJS to use. Defaults to "0.10.38". +* `system_packages` - (Optional) Names of a set of system packages to install on the layer's instances. +* `use_ebs_optimized_instances` - (Optional) Whether to use EBS-optimized instances. +* `ebs_volume` - (Optional) `ebs_volume` blocks, as described below, will each create an EBS volume and connect it to the layer's instances. + +The following extra optional arguments, all lists of Chef recipe names, allow +custom Chef recipes to be applied to layer instances at the five different +lifecycle events, if custom cookbooks are enabled on the layer's stack: + +* `custom_configure_recipes` +* `custom_deploy_recipes` +* `custom_setup_recipes` +* `custom_shutdown_recipes` +* `custom_undeploy_recipes` + +An `ebs_volume` block supports the following arguments: + +* `mount_point` - (Required) The path to mount the EBS volume on the layer's instances. +* `size` - (Required) The size of the volume in gigabytes. +* `number_of_disks` - (Required) The number of disks to use for the EBS volume. +* `raid_level` - (Required) The RAID level to use for the volume. +* `type` - (Optional) The type of volume to create. This may be `standard` (the default), `io1` or `gp2`. +* `iops` - (Optional) For PIOPS volumes, the IOPS per disk. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The id of the layer. diff --git a/website/source/docs/providers/aws/r/opsworks_php_app_layer.html.markdown b/website/source/docs/providers/aws/r/opsworks_php_app_layer.html.markdown new file mode 100644 index 0000000000..ec91e4ed36 --- /dev/null +++ b/website/source/docs/providers/aws/r/opsworks_php_app_layer.html.markdown @@ -0,0 +1,62 @@ +--- +layout: "aws" +page_title: "AWS: aws_opsworks_php_app_layer" +sidebar_current: "docs-aws-resource-opsworks-php-app-layer" +description: |- + Provides an OpsWorks PHP application layer resource. +--- + +# aws\_opsworks\_php\_app\_layer + +Provides an OpsWorks PHP application layer resource. + +## Example Usage + +``` +resource "aws_opsworks_php_app_layer" "app" { + stack_id = "${aws_opsworks_stack.main.id}" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `stack_id` - (Required) The id of the stack the layer will belong to. +* `name` - (Optional) A human-readable name for the layer. +* `auto_assign_elastic_ips` - (Optional) Whether to automatically assign an elastic IP address to the layer's instances. +* `auto_assign_public_ips` - (Optional) For stacks belonging to a VPC, whether to automatically assign a public IP address to each of the layer's instances. +* `custom_instance_profile_arn` - (Optional) The ARN of an IAM profile that will be used for the layer's instances. +* `custom_security_group_ids` - (Optional) Ids for a set of security groups to apply to the layer's instances. +* `auto_healing` - (Optional) Whether to enable auto-healing for the layer. +* `install_updates_on_boot` - (Optional) Whether to install OS and package updates on each instance when it boots. +* `instance_shutdown_timeout` - (Optional) The time, in seconds, that OpsWorks will wait for Chef to complete after triggering the Shutdown event. +* `drain_elb_on_shutdown` - (Optional) Whether to enable Elastic Load Balancing connection draining. +* `system_packages` - (Optional) Names of a set of system packages to install on the layer's instances. +* `use_ebs_optimized_instances` - (Optional) Whether to use EBS-optimized instances. +* `ebs_volume` - (Optional) `ebs_volume` blocks, as described below, will each create an EBS volume and connect it to the layer's instances. + +The following extra optional arguments, all lists of Chef recipe names, allow +custom Chef recipes to be applied to layer instances at the five different +lifecycle events, if custom cookbooks are enabled on the layer's stack: + +* `custom_configure_recipes` +* `custom_deploy_recipes` +* `custom_setup_recipes` +* `custom_shutdown_recipes` +* `custom_undeploy_recipes` + +An `ebs_volume` block supports the following arguments: + +* `mount_point` - (Required) The path to mount the EBS volume on the layer's instances. +* `size` - (Required) The size of the volume in gigabytes. +* `number_of_disks` - (Required) The number of disks to use for the EBS volume. +* `raid_level` - (Required) The RAID level to use for the volume. +* `type` - (Optional) The type of volume to create. This may be `standard` (the default), `io1` or `gp2`. +* `iops` - (Optional) For PIOPS volumes, the IOPS per disk. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The id of the layer. diff --git a/website/source/docs/providers/aws/r/opsworks_rails_app_layer.html.markdown b/website/source/docs/providers/aws/r/opsworks_rails_app_layer.html.markdown new file mode 100644 index 0000000000..ee4f85ed4c --- /dev/null +++ b/website/source/docs/providers/aws/r/opsworks_rails_app_layer.html.markdown @@ -0,0 +1,68 @@ +--- +layout: "aws" +page_title: "AWS: aws_opsworks_rails_app_layer" +sidebar_current: "docs-aws-resource-opsworks-rails-app-layer" +description: |- + Provides an OpsWorks Ruby on Rails application layer resource. +--- + +# aws\_opsworks\_rails\_app\_layer + +Provides an OpsWorks Ruby on Rails application layer resource. + +## Example Usage + +``` +resource "aws_opsworks_rails_app_layer" "app" { + stack_id = "${aws_opsworks_stack.main.id}" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `stack_id` - (Required) The id of the stack the layer will belong to. +* `name` - (Optional) A human-readable name for the layer. +* `app_server` - (Optional) Keyword for the app server to use. Defaults to "apache_passenger". +* `auto_assign_elastic_ips` - (Optional) Whether to automatically assign an elastic IP address to the layer's instances. +* `auto_assign_public_ips` - (Optional) For stacks belonging to a VPC, whether to automatically assign a public IP address to each of the layer's instances. +* `bundler_version` - (Optional) When OpsWorks is managing Bundler, which version to use. Defaults to "1.5.3". +* `custom_instance_profile_arn` - (Optional) The ARN of an IAM profile that will be used for the layer's instances. +* `custom_security_group_ids` - (Optional) Ids for a set of security groups to apply to the layer's instances. +* `auto_healing` - (Optional) Whether to enable auto-healing for the layer. +* `install_updates_on_boot` - (Optional) Whether to install OS and package updates on each instance when it boots. +* `instance_shutdown_timeout` - (Optional) The time, in seconds, that OpsWorks will wait for Chef to complete after triggering the Shutdown event. +* `drain_elb_on_shutdown` - (Optional) Whether to enable Elastic Load Balancing connection draining. +* `manage_bundler` - (Optional) Whether OpsWorks should manage bundler. On by default. +* `passenger_version` - (Optional) The version of Passenger to use. Defaults to "4.0.46". +* `ruby_version` - (Optional) The version of Ruby to use. Defaults to "2.0.0". +* `rubygems_version` - (Optional) The version of RubyGems to use. Defaults to "2.2.2". +* `system_packages` - (Optional) Names of a set of system packages to install on the layer's instances. +* `use_ebs_optimized_instances` - (Optional) Whether to use EBS-optimized instances. +* `ebs_volume` - (Optional) `ebs_volume` blocks, as described below, will each create an EBS volume and connect it to the layer's instances. + +The following extra optional arguments, all lists of Chef recipe names, allow +custom Chef recipes to be applied to layer instances at the five different +lifecycle events, if custom cookbooks are enabled on the layer's stack: + +* `custom_configure_recipes` +* `custom_deploy_recipes` +* `custom_setup_recipes` +* `custom_shutdown_recipes` +* `custom_undeploy_recipes` + +An `ebs_volume` block supports the following arguments: + +* `mount_point` - (Required) The path to mount the EBS volume on the layer's instances. +* `size` - (Required) The size of the volume in gigabytes. +* `number_of_disks` - (Required) The number of disks to use for the EBS volume. +* `raid_level` - (Required) The RAID level to use for the volume. +* `type` - (Optional) The type of volume to create. This may be `standard` (the default), `io1` or `gp2`. +* `iops` - (Optional) For PIOPS volumes, the IOPS per disk. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The id of the layer. diff --git a/website/source/docs/providers/aws/r/opsworks_stack.html.markdown b/website/source/docs/providers/aws/r/opsworks_stack.html.markdown new file mode 100644 index 0000000000..d664ca1a95 --- /dev/null +++ b/website/source/docs/providers/aws/r/opsworks_stack.html.markdown @@ -0,0 +1,68 @@ +--- +layout: "aws" +page_title: "AWS: aws_opsworks_stack" +sidebar_current: "docs-aws-resource-opsworks-stack" +description: |- + Provides an OpsWorks stack resource. +--- + +# aws\_opsworks\_stack + +Provides an OpsWorks stack resource. + +## Example Usage + +``` +resource "aws_opsworks_stack" "main" { + name = "awesome-stack" + region = "us-west-1" + service_role_arn = "${aws_iam_role.opsworks.arn}" + default_instance_profile_arn = "${aws_iam_instance_profile.opsworks.arn}" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the stack. +* `region` - (Required) The name of the region where the stack will exist. +* `service_role_arn` - (Required) The ARN of an IAM role that the OpsWorks service will act as. +* `default_instance_profile_arn` - (Required) The ARN of an IAM Instance Profile that created instances + will have by default. +* `berkshelf_version` - (Optional) If `manage_berkshelf` is enabled, the version of Berkshelf to use. +* `color` - (Optional) Color to paint next to the stack's resources in the OpsWorks console. +* `default_availability_zone` - (Optional) Name of the availability zone where instances will be created + by default. This is required unless you set `vpc_id`. +* `configuration_manager_name` - (Optional) Name of the configuration manager to use. Defaults to "Chef". +* `configuration_manager_version` - (Optional) Version of the configuratino manager to use. Defaults to "11.4". +* `custom_cookbooks_source` - (Optional) When `use_custom_cookbooks` is set, provide this sub-object as + described below. +* `default_os` - (Optional) Name of OS that will be installed on instances by default. +* `default_root_device_type` - (Optional) Name of the type of root device instances will have by default. +* `default_ssh_key_name` - (Optional) Name of the SSH keypair that instances will have by default. +* `default_subnet_id` - (Optional) Id of the subnet in which instances will be created by default. Mandatory + if `vpc_id` is set, and forbidden if it isn't. +* `hostname_theme` - (Optional) Keyword representing the naming scheme that will be used for instance hostnames + within this stack. +* `manage_berkshelf` - (Optional) Boolean value controlling whether Opsworks will run Berkshelf for this stack. +* `use_custom_cookbooks` - (Optional) Boolean value controlling whether the custom cookbook settings are + enabled. +* `use_opsworks_security_groups` - (Optional) Boolean value controlling whether the standard OpsWorks + security groups apply to created instances. +* `vpc_id` - (Optional) The id of the VPC that this stack belongs to. + +The `custom_cookbooks_source` block supports the following arguments: + +* `type` - (Required) The type of source to use. For example, "archive". +* `url` - (Required) The URL where the cookbooks resource can be found. +* `username` - (Optional) Username to use when authenticating to the source. +* `password` - (Optional) Password to use when authenticating to the source. +* `ssh_key` - (Optional) SSH key to use when authenticating to the source. +* `revision` - (Optional) For sources that are version-aware, the revision to use. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The id of the stack. diff --git a/website/source/docs/providers/aws/r/opsworks_static_web_layer.html.markdown b/website/source/docs/providers/aws/r/opsworks_static_web_layer.html.markdown new file mode 100644 index 0000000000..70272e8d07 --- /dev/null +++ b/website/source/docs/providers/aws/r/opsworks_static_web_layer.html.markdown @@ -0,0 +1,62 @@ +--- +layout: "aws" +page_title: "AWS: aws_opsworks_static_web_layer" +sidebar_current: "docs-aws-resource-opsworks-static-web-layer" +description: |- + Provides an OpsWorks static web server layer resource. +--- + +# aws\_opsworks\_static\_web\_layer + +Provides an OpsWorks static web server layer resource. + +## Example Usage + +``` +resource "aws_opsworks_static_web_layer" "web" { + stack_id = "${aws_opsworks_stack.main.id}" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `stack_id` - (Required) The id of the stack the layer will belong to. +* `name` - (Optional) A human-readable name for the layer. +* `auto_assign_elastic_ips` - (Optional) Whether to automatically assign an elastic IP address to the layer's instances. +* `auto_assign_public_ips` - (Optional) For stacks belonging to a VPC, whether to automatically assign a public IP address to each of the layer's instances. +* `custom_instance_profile_arn` - (Optional) The ARN of an IAM profile that will be used for the layer's instances. +* `custom_security_group_ids` - (Optional) Ids for a set of security groups to apply to the layer's instances. +* `auto_healing` - (Optional) Whether to enable auto-healing for the layer. +* `install_updates_on_boot` - (Optional) Whether to install OS and package updates on each instance when it boots. +* `instance_shutdown_timeout` - (Optional) The time, in seconds, that OpsWorks will wait for Chef to complete after triggering the Shutdown event. +* `drain_elb_on_shutdown` - (Optional) Whether to enable Elastic Load Balancing connection draining. +* `system_packages` - (Optional) Names of a set of system packages to install on the layer's instances. +* `use_ebs_optimized_instances` - (Optional) Whether to use EBS-optimized instances. +* `ebs_volume` - (Optional) `ebs_volume` blocks, as described below, will each create an EBS volume and connect it to the layer's instances. + +The following extra optional arguments, all lists of Chef recipe names, allow +custom Chef recipes to be applied to layer instances at the five different +lifecycle events, if custom cookbooks are enabled on the layer's stack: + +* `custom_configure_recipes` +* `custom_deploy_recipes` +* `custom_setup_recipes` +* `custom_shutdown_recipes` +* `custom_undeploy_recipes` + +An `ebs_volume` block supports the following arguments: + +* `mount_point` - (Required) The path to mount the EBS volume on the layer's instances. +* `size` - (Required) The size of the volume in gigabytes. +* `number_of_disks` - (Required) The number of disks to use for the EBS volume. +* `raid_level` - (Required) The RAID level to use for the volume. +* `type` - (Optional) The type of volume to create. This may be `standard` (the default), `io1` or `gp2`. +* `iops` - (Optional) For PIOPS volumes, the IOPS per disk. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The id of the layer. diff --git a/website/source/layouts/aws.erb b/website/source/layouts/aws.erb index 17281a9f84..296463206c 100644 --- a/website/source/layouts/aws.erb +++ b/website/source/layouts/aws.erb @@ -22,7 +22,7 @@