mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
aws_opswork_stack resource type.
"Stack" is the root concept in OpsWorks, and acts as a container for a number of different "layers" that each provide some service for an application. A stack isn't very interesting on its own, but it needs to be created before any layers can be created.
This commit is contained in:
parent
8e79f0cb3a
commit
4ce3d089fb
@ -207,6 +207,7 @@ func Provider() terraform.ResourceProvider {
|
|||||||
"aws_main_route_table_association": resourceAwsMainRouteTableAssociation(),
|
"aws_main_route_table_association": resourceAwsMainRouteTableAssociation(),
|
||||||
"aws_network_acl": resourceAwsNetworkAcl(),
|
"aws_network_acl": resourceAwsNetworkAcl(),
|
||||||
"aws_network_interface": resourceAwsNetworkInterface(),
|
"aws_network_interface": resourceAwsNetworkInterface(),
|
||||||
|
"aws_opsworks_stack": resourceAwsOpsworksStack(),
|
||||||
"aws_proxy_protocol_policy": resourceAwsProxyProtocolPolicy(),
|
"aws_proxy_protocol_policy": resourceAwsProxyProtocolPolicy(),
|
||||||
"aws_route53_delegation_set": resourceAwsRoute53DelegationSet(),
|
"aws_route53_delegation_set": resourceAwsRoute53DelegationSet(),
|
||||||
"aws_route53_record": resourceAwsRoute53Record(),
|
"aws_route53_record": resourceAwsRoute53Record(),
|
||||||
|
456
builtin/providers/aws/resource_aws_opsworks_stack.go
Normal file
456
builtin/providers/aws/resource_aws_opsworks_stack.go
Normal file
@ -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
|
||||||
|
}
|
353
builtin/providers/aws/resource_aws_opsworks_stack_test.go
Normal file
353
builtin/providers/aws/resource_aws_opsworks_stack_test.go
Normal file
@ -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
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -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.
|
@ -259,6 +259,10 @@
|
|||||||
<a href="#">OpsWorks Resources</a>
|
<a href="#">OpsWorks Resources</a>
|
||||||
<ul class="nav nav-visible">
|
<ul class="nav nav-visible">
|
||||||
|
|
||||||
|
<li<%= sidebar_current("docs-aws-resource-opsworks-stack") %>>
|
||||||
|
<a href="/docs/providers/aws/r/opsworks_stack.html">aws_opsworks_stack</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user