Merge branch 'master' into f-aws-flow-logs
* master: Update CHANGELOG.md Update CHANGELOG.md Added affinity group resource. update link to actually work provider/azure: Fix SQL client name to match upstream add warning message to explain scenario of conflicting rules typo remove debugging Update CHANGELOG.md provider/aws: Add docs for autoscaling_policy + cloudwatch_metric_alarm provider/aws: Add autoscaling_policy provider/aws: Add cloudwatch_metric_alarm rename method, update docs clean up some conflicts with clean up old, incompatible test update tests with another example update test remove meta usage, stub test fix existing tests Consider security groups with source security groups when hashing
This commit is contained in:
commit
cc43ae8c4b
|
@ -2,8 +2,10 @@
|
|||
|
||||
FEATURES:
|
||||
|
||||
* **New provider: `azure`** [GH-2052, GH-2053, GH-2372, GH-2380]
|
||||
* **New provider: `azure`** [GH-2052, GH-2053, GH-2372, GH-2380, GH-2394]
|
||||
* **New resource: `aws_autoscaling_notification`** [GH-2197]
|
||||
* **New resource: `aws_autoscaling_policy`** [GH-2201]
|
||||
* **New resource: `aws_cloudwatch_metric_alarm`** [GH-2201]
|
||||
* **New resource: `aws_dynamodb_table`** [GH-2121]
|
||||
* **New resource: `aws_ecs_cluster`** [GH-1803]
|
||||
* **New resource: `aws_ecs_service`** [GH-1803]
|
||||
|
@ -35,6 +37,8 @@ BUG FIXES:
|
|||
* command/apply: prevent output duplication when reporting errors [GH-2267]
|
||||
* provider/aws: fix panic when route has no cidr_block [GH-2215]
|
||||
* provider/aws: fix issue preventing destruction of IAM Roles [GH-2177]
|
||||
* provider/aws: fix issue where Security Group Rules could collide and fail
|
||||
to save to the state file correctly [GH-2376]
|
||||
* provider/aws: fix issue preventing destruction self referencing Securtity
|
||||
Group Rules [GH-2305]
|
||||
* provider/aws: fix issue causing perpetual diff on ELB listeners
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/service/autoscaling"
|
||||
"github.com/aws/aws-sdk-go/service/cloudwatch"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/aws/aws-sdk-go/service/ecs"
|
||||
|
@ -37,6 +38,7 @@ type Config struct {
|
|||
}
|
||||
|
||||
type AWSClient struct {
|
||||
cloudwatchconn *cloudwatch.CloudWatch
|
||||
dynamodbconn *dynamodb.DynamoDB
|
||||
ec2conn *ec2.EC2
|
||||
ecsconn *ecs.ECS
|
||||
|
@ -143,6 +145,9 @@ func (c *Config) Client() (interface{}, error) {
|
|||
|
||||
log.Println("[INFO] Initializing Lambda Connection")
|
||||
client.lambdaconn = lambda.New(awsConfig)
|
||||
|
||||
log.Println("[INFO] Initializing CloudWatch SDK connection")
|
||||
client.cloudwatchconn = cloudwatch.New(awsConfig)
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
|
|
|
@ -86,6 +86,8 @@ func Provider() terraform.ResourceProvider {
|
|||
"aws_app_cookie_stickiness_policy": resourceAwsAppCookieStickinessPolicy(),
|
||||
"aws_autoscaling_group": resourceAwsAutoscalingGroup(),
|
||||
"aws_autoscaling_notification": resourceAwsAutoscalingNotification(),
|
||||
"aws_autoscaling_policy": resourceAwsAutoscalingPolicy(),
|
||||
"aws_cloudwatch_metric_alarm": resourceAwsCloudWatchMetricAlarm(),
|
||||
"aws_customer_gateway": resourceAwsCustomerGateway(),
|
||||
"aws_db_instance": resourceAwsDbInstance(),
|
||||
"aws_db_parameter_group": resourceAwsDbParameterGroup(),
|
||||
|
|
|
@ -408,7 +408,7 @@ func waitForASGCapacity(d *schema.ResourceData, meta interface{}) error {
|
|||
}
|
||||
wantELB := d.Get("min_elb_capacity").(int)
|
||||
|
||||
log.Printf("[DEBUG] Wanting for capacity: %d ASG, %d ELB", wantASG, wantELB)
|
||||
log.Printf("[DEBUG] Waiting for capacity: %d ASG, %d ELB", wantASG, wantELB)
|
||||
|
||||
return resource.Retry(waitForASGCapacityTimeout, func() error {
|
||||
g, err := getAwsAutoscalingGroup(d, meta)
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/autoscaling"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func resourceAwsAutoscalingPolicy() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceAwsAutoscalingPolicyCreate,
|
||||
Read: resourceAwsAutoscalingPolicyRead,
|
||||
Update: resourceAwsAutoscalingPolicyUpdate,
|
||||
Delete: resourceAwsAutoscalingPolicyDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"arn": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"adjustment_type": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"autoscaling_group_name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"cooldown": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
},
|
||||
"min_adjustment_step": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
},
|
||||
"scaling_adjustment": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceAwsAutoscalingPolicyCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
autoscalingconn := meta.(*AWSClient).autoscalingconn
|
||||
|
||||
params := getAwsAutoscalingPutScalingPolicyInput(d)
|
||||
|
||||
log.Printf("[DEBUG] AutoScaling PutScalingPolicy: %#v", params)
|
||||
resp, err := autoscalingconn.PutScalingPolicy(¶ms)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error putting scaling policy: %s", err)
|
||||
}
|
||||
|
||||
d.Set("arn", resp.PolicyARN)
|
||||
d.SetId(d.Get("name").(string))
|
||||
log.Printf("[INFO] AutoScaling Scaling PolicyARN: %s", d.Get("arn").(string))
|
||||
|
||||
return resourceAwsAutoscalingPolicyRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceAwsAutoscalingPolicyRead(d *schema.ResourceData, meta interface{}) error {
|
||||
p, err := getAwsAutoscalingPolicy(d, meta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if p == nil {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Read Scaling Policy: ASG: %s, SP: %s, Obj: %#v", d.Get("autoscaling_group_name"), d.Get("name"), p)
|
||||
|
||||
d.Set("adjustment_type", p.AdjustmentType)
|
||||
d.Set("autoscaling_group_name", p.AutoScalingGroupName)
|
||||
d.Set("cooldown", p.Cooldown)
|
||||
d.Set("min_adjustment_step", p.MinAdjustmentStep)
|
||||
d.Set("arn", p.PolicyARN)
|
||||
d.Set("name", p.PolicyName)
|
||||
d.Set("scaling_adjustment", p.ScalingAdjustment)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAwsAutoscalingPolicyUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
autoscalingconn := meta.(*AWSClient).autoscalingconn
|
||||
|
||||
params := getAwsAutoscalingPutScalingPolicyInput(d)
|
||||
|
||||
log.Printf("[DEBUG] Autoscaling Update Scaling Policy: %#v", params)
|
||||
_, err := autoscalingconn.PutScalingPolicy(¶ms)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return resourceAwsAutoscalingPolicyRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceAwsAutoscalingPolicyDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
autoscalingconn := meta.(*AWSClient).autoscalingconn
|
||||
p, err := getAwsAutoscalingPolicy(d, meta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if p == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
params := autoscaling.DeletePolicyInput{
|
||||
AutoScalingGroupName: aws.String(d.Get("autoscaling_group_name").(string)),
|
||||
PolicyName: aws.String(d.Get("name").(string)),
|
||||
}
|
||||
if _, err := autoscalingconn.DeletePolicy(¶ms); err != nil {
|
||||
return fmt.Errorf("Autoscaling Scaling Policy: %s ", err)
|
||||
}
|
||||
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
// PutScalingPolicy seems to require all params to be resent, so create and update can share this common function
|
||||
func getAwsAutoscalingPutScalingPolicyInput(d *schema.ResourceData) autoscaling.PutScalingPolicyInput {
|
||||
var params = autoscaling.PutScalingPolicyInput{
|
||||
AutoScalingGroupName: aws.String(d.Get("autoscaling_group_name").(string)),
|
||||
PolicyName: aws.String(d.Get("name").(string)),
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk("adjustment_type"); ok {
|
||||
params.AdjustmentType = aws.String(v.(string))
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk("cooldown"); ok {
|
||||
params.Cooldown = aws.Long(int64(v.(int)))
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk("scaling_adjustment"); ok {
|
||||
params.ScalingAdjustment = aws.Long(int64(v.(int)))
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk("min_adjustment_step"); ok {
|
||||
params.MinAdjustmentStep = aws.Long(int64(v.(int)))
|
||||
}
|
||||
|
||||
return params
|
||||
}
|
||||
|
||||
func getAwsAutoscalingPolicy(d *schema.ResourceData, meta interface{}) (*autoscaling.ScalingPolicy, error) {
|
||||
autoscalingconn := meta.(*AWSClient).autoscalingconn
|
||||
|
||||
params := autoscaling.DescribePoliciesInput{
|
||||
AutoScalingGroupName: aws.String(d.Get("autoscaling_group_name").(string)),
|
||||
PolicyNames: []*string{aws.String(d.Get("name").(string))},
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] AutoScaling Scaling Policy Describe Params: %#v", params)
|
||||
resp, err := autoscalingconn.DescribePolicies(¶ms)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error retrieving scaling policies: %s", err)
|
||||
}
|
||||
|
||||
// find scaling policy
|
||||
name := d.Get("name")
|
||||
for idx, sp := range resp.ScalingPolicies {
|
||||
if *sp.PolicyName == name {
|
||||
return resp.ScalingPolicies[idx], nil
|
||||
}
|
||||
}
|
||||
|
||||
// policy not found
|
||||
return nil, nil
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/autoscaling"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccAWSAutoscalingPolicy_basic(t *testing.T) {
|
||||
var policy autoscaling.ScalingPolicy
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSAutoscalingPolicyDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAWSAutoscalingPolicyConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckScalingPolicyExists("aws_autoscaling_policy.foobar", &policy),
|
||||
resource.TestCheckResourceAttr("aws_autoscaling_policy.foobar", "adjustment_type", "ChangeInCapacity"),
|
||||
resource.TestCheckResourceAttr("aws_autoscaling_policy.foobar", "cooldown", "300"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckScalingPolicyExists(n string, policy *autoscaling.ScalingPolicy) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[n]
|
||||
if !ok {
|
||||
rs = rs
|
||||
return fmt.Errorf("Not found: %s", n)
|
||||
}
|
||||
|
||||
conn := testAccProvider.Meta().(*AWSClient).autoscalingconn
|
||||
params := &autoscaling.DescribePoliciesInput{
|
||||
AutoScalingGroupName: aws.String(rs.Primary.Attributes["autoscaling_group_name"]),
|
||||
PolicyNames: []*string{aws.String(rs.Primary.ID)},
|
||||
}
|
||||
resp, err := conn.DescribePolicies(params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(resp.ScalingPolicies) == 0 {
|
||||
return fmt.Errorf("ScalingPolicy not found")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckAWSAutoscalingPolicyDestroy(s *terraform.State) error {
|
||||
conn := testAccProvider.Meta().(*AWSClient).autoscalingconn
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "aws_autoscaling_group" {
|
||||
continue
|
||||
}
|
||||
|
||||
params := autoscaling.DescribePoliciesInput{
|
||||
AutoScalingGroupName: aws.String(rs.Primary.Attributes["autoscaling_group_name"]),
|
||||
PolicyNames: []*string{aws.String(rs.Primary.ID)},
|
||||
}
|
||||
|
||||
resp, err := conn.DescribePolicies(¶ms)
|
||||
|
||||
if err == nil {
|
||||
if len(resp.ScalingPolicies) != 0 &&
|
||||
*resp.ScalingPolicies[0].PolicyName == rs.Primary.ID {
|
||||
return fmt.Errorf("Scaling Policy Still Exists: %s", rs.Primary.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var testAccAWSAutoscalingPolicyConfig = fmt.Sprintf(`
|
||||
resource "aws_launch_configuration" "foobar" {
|
||||
name = "terraform-test-foobar5"
|
||||
image_id = "ami-21f78e11"
|
||||
instance_type = "t1.micro"
|
||||
}
|
||||
|
||||
resource "aws_autoscaling_group" "foobar" {
|
||||
availability_zones = ["us-west-2a"]
|
||||
name = "terraform-test-foobar5"
|
||||
max_size = 5
|
||||
min_size = 2
|
||||
health_check_grace_period = 300
|
||||
health_check_type = "ELB"
|
||||
force_delete = true
|
||||
termination_policies = ["OldestInstance"]
|
||||
launch_configuration = "${aws_launch_configuration.foobar.name}"
|
||||
tag {
|
||||
key = "Foo"
|
||||
value = "foo-bar"
|
||||
propagate_at_launch = true
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_autoscaling_policy" "foobar" {
|
||||
name = "foobar"
|
||||
scaling_adjustment = 4
|
||||
adjustment_type = "ChangeInCapacity"
|
||||
cooldown = 300
|
||||
autoscaling_group_name = "${aws_autoscaling_group.foobar.name}"
|
||||
}
|
||||
`)
|
|
@ -0,0 +1,288 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"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/service/cloudwatch"
|
||||
)
|
||||
|
||||
func resourceAwsCloudWatchMetricAlarm() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceAwsCloudWatchMetricAlarmCreate,
|
||||
Read: resourceAwsCloudWatchMetricAlarmRead,
|
||||
Update: resourceAwsCloudWatchMetricAlarmUpdate,
|
||||
Delete: resourceAwsCloudWatchMetricAlarmDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"alarm_name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"comparison_operator": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"evaluation_periods": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
},
|
||||
"metric_name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"namespace": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"period": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
},
|
||||
"statistic": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"threshold": &schema.Schema{
|
||||
Type: schema.TypeFloat,
|
||||
Required: true,
|
||||
},
|
||||
"actions_enabled": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: true,
|
||||
},
|
||||
"alarm_actions": &schema.Schema{
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
Set: func(v interface{}) int {
|
||||
return hashcode.String(v.(string))
|
||||
},
|
||||
},
|
||||
"alarm_description": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
"dimensions": &schema.Schema{
|
||||
Type: schema.TypeMap,
|
||||
Optional: true,
|
||||
},
|
||||
"insufficient_data_actions": &schema.Schema{
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
Set: func(v interface{}) int {
|
||||
return hashcode.String(v.(string))
|
||||
},
|
||||
},
|
||||
"ok_actions": &schema.Schema{
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
Set: func(v interface{}) int {
|
||||
return hashcode.String(v.(string))
|
||||
},
|
||||
},
|
||||
"unit": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceAwsCloudWatchMetricAlarmCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).cloudwatchconn
|
||||
|
||||
params := getAwsCloudWatchPutMetricAlarmInput(d)
|
||||
|
||||
log.Printf("[DEBUG] Creating CloudWatch Metric Alarm: %#v", params)
|
||||
_, err := conn.PutMetricAlarm(¶ms)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Creating metric alarm failed: %s", err)
|
||||
}
|
||||
d.SetId(d.Get("alarm_name").(string))
|
||||
log.Println("[INFO] CloudWatch Metric Alarm created")
|
||||
|
||||
return resourceAwsCloudWatchMetricAlarmRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceAwsCloudWatchMetricAlarmRead(d *schema.ResourceData, meta interface{}) error {
|
||||
a, err := getAwsCloudWatchMetricAlarm(d, meta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if a == nil {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Reading CloudWatch Metric Alarm: %s", d.Get("alarm_name"))
|
||||
|
||||
d.Set("actions_enabled", a.ActionsEnabled)
|
||||
|
||||
if err := d.Set("alarm_actions", _strArrPtrToList(a.AlarmActions)); err != nil {
|
||||
log.Printf("[WARN] Error setting Alarm Actions: %s", err)
|
||||
}
|
||||
d.Set("alarm_description", a.AlarmDescription)
|
||||
d.Set("alarm_name", a.AlarmName)
|
||||
d.Set("comparison_operator", a.ComparisonOperator)
|
||||
d.Set("dimensions", a.Dimensions)
|
||||
d.Set("evaluation_periods", a.EvaluationPeriods)
|
||||
|
||||
if err := d.Set("insufficient_data_actions", _strArrPtrToList(a.InsufficientDataActions)); err != nil {
|
||||
log.Printf("[WARN] Error setting Insufficient Data Actions: %s", err)
|
||||
}
|
||||
d.Set("metric_name", a.MetricName)
|
||||
d.Set("namespace", a.Namespace)
|
||||
|
||||
if err := d.Set("ok_actions", _strArrPtrToList(a.OKActions)); err != nil {
|
||||
log.Printf("[WARN] Error setting OK Actions: %s", err)
|
||||
}
|
||||
d.Set("period", a.Period)
|
||||
d.Set("statistic", a.Statistic)
|
||||
d.Set("threshold", a.Threshold)
|
||||
d.Set("unit", a.Unit)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAwsCloudWatchMetricAlarmUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).cloudwatchconn
|
||||
params := getAwsCloudWatchPutMetricAlarmInput(d)
|
||||
|
||||
log.Printf("[DEBUG] Updating CloudWatch Metric Alarm: %#v", params)
|
||||
_, err := conn.PutMetricAlarm(¶ms)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Updating metric alarm failed: %s", err)
|
||||
}
|
||||
log.Println("[INFO] CloudWatch Metric Alarm updated")
|
||||
|
||||
return resourceAwsCloudWatchMetricAlarmRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceAwsCloudWatchMetricAlarmDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
p, err := getAwsCloudWatchMetricAlarm(d, meta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if p == nil {
|
||||
log.Printf("[DEBUG] CloudWatch Metric Alarm %s is already gone", d.Id())
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Deleting CloudWatch Metric Alarm: %s", d.Id())
|
||||
|
||||
conn := meta.(*AWSClient).cloudwatchconn
|
||||
params := cloudwatch.DeleteAlarmsInput{
|
||||
AlarmNames: []*string{aws.String(d.Id())},
|
||||
}
|
||||
|
||||
if _, err := conn.DeleteAlarms(¶ms); err != nil {
|
||||
return fmt.Errorf("Error deleting CloudWatch Metric Alarm: %s", err)
|
||||
}
|
||||
log.Println("[INFO] CloudWatch Metric Alarm deleted")
|
||||
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
func getAwsCloudWatchPutMetricAlarmInput(d *schema.ResourceData) cloudwatch.PutMetricAlarmInput {
|
||||
params := cloudwatch.PutMetricAlarmInput{
|
||||
AlarmName: aws.String(d.Get("alarm_name").(string)),
|
||||
ComparisonOperator: aws.String(d.Get("comparison_operator").(string)),
|
||||
EvaluationPeriods: aws.Long(int64(d.Get("evaluation_periods").(int))),
|
||||
MetricName: aws.String(d.Get("metric_name").(string)),
|
||||
Namespace: aws.String(d.Get("namespace").(string)),
|
||||
Period: aws.Long(int64(d.Get("period").(int))),
|
||||
Statistic: aws.String(d.Get("statistic").(string)),
|
||||
Threshold: aws.Double(d.Get("threshold").(float64)),
|
||||
}
|
||||
|
||||
if v := d.Get("actions_enabled"); v != nil {
|
||||
params.ActionsEnabled = aws.Boolean(v.(bool))
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk("alarm_description"); ok {
|
||||
params.AlarmDescription = aws.String(v.(string))
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk("unit"); ok {
|
||||
params.Unit = aws.String(v.(string))
|
||||
}
|
||||
|
||||
var alarmActions []*string
|
||||
if v := d.Get("alarm_actions"); v != nil {
|
||||
for _, v := range v.(*schema.Set).List() {
|
||||
str := v.(string)
|
||||
alarmActions = append(alarmActions, aws.String(str))
|
||||
}
|
||||
params.AlarmActions = alarmActions
|
||||
}
|
||||
|
||||
var insufficientDataActions []*string
|
||||
if v := d.Get("insufficient_data_actions"); v != nil {
|
||||
for _, v := range v.(*schema.Set).List() {
|
||||
str := v.(string)
|
||||
insufficientDataActions = append(insufficientDataActions, aws.String(str))
|
||||
}
|
||||
params.InsufficientDataActions = insufficientDataActions
|
||||
}
|
||||
|
||||
var okActions []*string
|
||||
if v := d.Get("ok_actions"); v != nil {
|
||||
for _, v := range v.(*schema.Set).List() {
|
||||
str := v.(string)
|
||||
okActions = append(okActions, aws.String(str))
|
||||
}
|
||||
params.OKActions = okActions
|
||||
}
|
||||
|
||||
a := d.Get("dimensions").(map[string]interface{})
|
||||
dimensions := make([]*cloudwatch.Dimension, 0, len(a))
|
||||
for k, v := range a {
|
||||
dimensions = append(dimensions, &cloudwatch.Dimension{
|
||||
Name: aws.String(k),
|
||||
Value: aws.String(v.(string)),
|
||||
})
|
||||
}
|
||||
params.Dimensions = dimensions
|
||||
|
||||
return params
|
||||
}
|
||||
|
||||
func getAwsCloudWatchMetricAlarm(d *schema.ResourceData, meta interface{}) (*cloudwatch.MetricAlarm, error) {
|
||||
conn := meta.(*AWSClient).cloudwatchconn
|
||||
|
||||
params := cloudwatch.DescribeAlarmsInput{
|
||||
AlarmNames: []*string{aws.String(d.Id())},
|
||||
}
|
||||
|
||||
resp, err := conn.DescribeAlarms(¶ms)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Find it and return it
|
||||
for idx, ma := range resp.MetricAlarms {
|
||||
if *ma.AlarmName == d.Id() {
|
||||
return resp.MetricAlarms[idx], nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func _strArrPtrToList(strArrPtr []*string) []string {
|
||||
var result []string
|
||||
for _, elem := range strArrPtr {
|
||||
result = append(result, *elem)
|
||||
}
|
||||
return result
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/cloudwatch"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccAWSCloudWatchMetricAlarm_basic(t *testing.T) {
|
||||
var alarm cloudwatch.MetricAlarm
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSCloudWatchMetricAlarmDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAWSCloudWatchMetricAlarmConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudWatchMetricAlarmExists("aws_cloudwatch_metric_alarm.foobar", &alarm),
|
||||
resource.TestCheckResourceAttr("aws_cloudwatch_metric_alarm.foobar", "metric_name", "CPUUtilization"),
|
||||
resource.TestCheckResourceAttr("aws_cloudwatch_metric_alarm.foobar", "statistic", "Average"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckCloudWatchMetricAlarmExists(n string, alarm *cloudwatch.MetricAlarm) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[n]
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", n)
|
||||
}
|
||||
|
||||
conn := testAccProvider.Meta().(*AWSClient).cloudwatchconn
|
||||
params := cloudwatch.DescribeAlarmsInput{
|
||||
AlarmNames: []*string{aws.String(rs.Primary.ID)},
|
||||
}
|
||||
resp, err := conn.DescribeAlarms(¶ms)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(resp.MetricAlarms) == 0 {
|
||||
return fmt.Errorf("Alarm not found")
|
||||
}
|
||||
*alarm = *resp.MetricAlarms[0]
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckAWSCloudWatchMetricAlarmDestroy(s *terraform.State) error {
|
||||
conn := testAccProvider.Meta().(*AWSClient).cloudwatchconn
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "aws_cloudwatch_metric_alarm" {
|
||||
continue
|
||||
}
|
||||
|
||||
params := cloudwatch.DescribeAlarmsInput{
|
||||
AlarmNames: []*string{aws.String(rs.Primary.ID)},
|
||||
}
|
||||
|
||||
resp, err := conn.DescribeAlarms(¶ms)
|
||||
|
||||
if err == nil {
|
||||
if len(resp.MetricAlarms) != 0 &&
|
||||
*resp.MetricAlarms[0].AlarmName == rs.Primary.ID {
|
||||
return fmt.Errorf("Alarm Still Exists: %s", rs.Primary.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var testAccAWSCloudWatchMetricAlarmConfig = fmt.Sprintf(`
|
||||
resource "aws_cloudwatch_metric_alarm" "foobar" {
|
||||
alarm_name = "terraform-test-foobar5"
|
||||
comparison_operator = "GreaterThanOrEqualToThreshold"
|
||||
evaluation_periods = "2"
|
||||
metric_name = "CPUUtilization"
|
||||
namespace = "AWS/EC2"
|
||||
period = "120"
|
||||
statistic = "Average"
|
||||
threshold = "80"
|
||||
alarm_description = "This metric monitor ec2 cpu utilization"
|
||||
insufficient_data_actions = []
|
||||
}
|
||||
`)
|
|
@ -21,6 +21,9 @@ func resourceAwsSecurityGroupRule() *schema.Resource {
|
|||
Read: resourceAwsSecurityGroupRuleRead,
|
||||
Delete: resourceAwsSecurityGroupRuleDelete,
|
||||
|
||||
SchemaVersion: 1,
|
||||
MigrateState: resourceAwsSecurityGroupRuleMigrateState,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"type": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
|
@ -61,10 +64,11 @@ func resourceAwsSecurityGroupRule() *schema.Resource {
|
|||
},
|
||||
|
||||
"source_security_group_id": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Computed: true,
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Computed: true,
|
||||
ConflictsWith: []string{"cidr_blocks"},
|
||||
},
|
||||
|
||||
"self": &schema.Schema{
|
||||
|
@ -90,6 +94,7 @@ func resourceAwsSecurityGroupRuleCreate(d *schema.ResourceData, meta interface{}
|
|||
|
||||
ruleType := d.Get("type").(string)
|
||||
|
||||
var autherr error
|
||||
switch ruleType {
|
||||
case "ingress":
|
||||
log.Printf("[DEBUG] Authorizing security group %s %s rule: %s",
|
||||
|
@ -105,13 +110,7 @@ func resourceAwsSecurityGroupRuleCreate(d *schema.ResourceData, meta interface{}
|
|||
req.GroupName = sg.GroupName
|
||||
}
|
||||
|
||||
_, err := conn.AuthorizeSecurityGroupIngress(req)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error authorizing security group %s rules: %s",
|
||||
"rules", err)
|
||||
}
|
||||
_, autherr = conn.AuthorizeSecurityGroupIngress(req)
|
||||
|
||||
case "egress":
|
||||
log.Printf("[DEBUG] Authorizing security group %s %s rule: %#v",
|
||||
|
@ -122,18 +121,28 @@ func resourceAwsSecurityGroupRuleCreate(d *schema.ResourceData, meta interface{}
|
|||
IPPermissions: []*ec2.IPPermission{perm},
|
||||
}
|
||||
|
||||
_, err = conn.AuthorizeSecurityGroupEgress(req)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error authorizing security group %s rules: %s",
|
||||
"rules", err)
|
||||
}
|
||||
_, autherr = conn.AuthorizeSecurityGroupEgress(req)
|
||||
|
||||
default:
|
||||
return fmt.Errorf("Security Group Rule must be type 'ingress' or type 'egress'")
|
||||
}
|
||||
|
||||
if autherr != nil {
|
||||
if awsErr, ok := autherr.(awserr.Error); ok {
|
||||
if awsErr.Code() == "InvalidPermission.Duplicate" {
|
||||
return fmt.Errorf(`[WARN] A duplicate Security Group rule was found. This may be
|
||||
a side effect of a now-fixed Terraform issue causing two security groups with
|
||||
identical attributes but different source_security_group_ids to overwrite each
|
||||
other in the state. See https://github.com/hashicorp/terraform/pull/2376 for more
|
||||
information and instructions for recovery. Error message: %s`, awsErr.Message())
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf(
|
||||
"Error authorizing security group rule type %s: %s",
|
||||
ruleType, autherr)
|
||||
}
|
||||
|
||||
d.SetId(ipPermissionIDHash(ruleType, perm))
|
||||
|
||||
return resourceAwsSecurityGroupRuleRead(d, meta)
|
||||
|
@ -263,15 +272,32 @@ func findResourceSecurityGroup(conn *ec2.EC2, id string) (*ec2.SecurityGroup, er
|
|||
return resp.SecurityGroups[0], nil
|
||||
}
|
||||
|
||||
// ByGroupPair implements sort.Interface for []*ec2.UserIDGroupPairs based on
|
||||
// GroupID or GroupName field (only one should be set).
|
||||
type ByGroupPair []*ec2.UserIDGroupPair
|
||||
|
||||
func (b ByGroupPair) Len() int { return len(b) }
|
||||
func (b ByGroupPair) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
|
||||
func (b ByGroupPair) Less(i, j int) bool {
|
||||
if b[i].GroupID != nil && b[j].GroupID != nil {
|
||||
return *b[i].GroupID < *b[j].GroupID
|
||||
}
|
||||
if b[i].GroupName != nil && b[j].GroupName != nil {
|
||||
return *b[i].GroupName < *b[j].GroupName
|
||||
}
|
||||
|
||||
panic("mismatched security group rules, may be a terraform bug")
|
||||
}
|
||||
|
||||
func ipPermissionIDHash(ruleType string, ip *ec2.IPPermission) string {
|
||||
var buf bytes.Buffer
|
||||
// for egress rules, an TCP rule of -1 is automatically added, in which case
|
||||
// the to and from ports will be nil. We don't record this rule locally.
|
||||
if ip.IPProtocol != nil && *ip.IPProtocol != "-1" {
|
||||
if ip.FromPort != nil && *ip.FromPort > 0 {
|
||||
buf.WriteString(fmt.Sprintf("%d-", *ip.FromPort))
|
||||
buf.WriteString(fmt.Sprintf("%d-", *ip.ToPort))
|
||||
buf.WriteString(fmt.Sprintf("%s-", *ip.IPProtocol))
|
||||
}
|
||||
if ip.ToPort != nil && *ip.ToPort > 0 {
|
||||
buf.WriteString(fmt.Sprintf("%d-", *ip.ToPort))
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf("%s-", *ip.IPProtocol))
|
||||
buf.WriteString(fmt.Sprintf("%s-", ruleType))
|
||||
|
||||
// We need to make sure to sort the strings below so that we always
|
||||
|
@ -288,6 +314,22 @@ func ipPermissionIDHash(ruleType string, ip *ec2.IPPermission) string {
|
|||
}
|
||||
}
|
||||
|
||||
if len(ip.UserIDGroupPairs) > 0 {
|
||||
sort.Sort(ByGroupPair(ip.UserIDGroupPairs))
|
||||
for _, pair := range ip.UserIDGroupPairs {
|
||||
if pair.GroupID != nil {
|
||||
buf.WriteString(fmt.Sprintf("%s-", *pair.GroupID))
|
||||
} else {
|
||||
buf.WriteString("-")
|
||||
}
|
||||
if pair.GroupName != nil {
|
||||
buf.WriteString(fmt.Sprintf("%s-", *pair.GroupName))
|
||||
} else {
|
||||
buf.WriteString("-")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("sg-%d", hashcode.String(buf.String()))
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func resourceAwsSecurityGroupRuleMigrateState(
|
||||
v int, is *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) {
|
||||
switch v {
|
||||
case 0:
|
||||
log.Println("[INFO] Found AWS Security Group State v0; migrating to v1")
|
||||
return migrateSGRuleStateV0toV1(is)
|
||||
default:
|
||||
return is, fmt.Errorf("Unexpected schema version: %d", v)
|
||||
}
|
||||
|
||||
return is, nil
|
||||
}
|
||||
|
||||
func migrateSGRuleStateV0toV1(is *terraform.InstanceState) (*terraform.InstanceState, error) {
|
||||
if is.Empty() {
|
||||
log.Println("[DEBUG] Empty InstanceState; nothing to migrate.")
|
||||
return is, nil
|
||||
}
|
||||
|
||||
perm, err := migrateExpandIPPerm(is.Attributes)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[WARN] Error making new IP Permission in Security Group migration")
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Attributes before migration: %#v", is.Attributes)
|
||||
newID := ipPermissionIDHash(is.Attributes["type"], perm)
|
||||
is.Attributes["id"] = newID
|
||||
is.ID = newID
|
||||
log.Printf("[DEBUG] Attributes after migration: %#v, new id: %s", is.Attributes, newID)
|
||||
return is, nil
|
||||
}
|
||||
|
||||
func migrateExpandIPPerm(attrs map[string]string) (*ec2.IPPermission, error) {
|
||||
var perm ec2.IPPermission
|
||||
tp, err := strconv.Atoi(attrs["to_port"])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error converting to_port in Security Group migration")
|
||||
}
|
||||
|
||||
fp, err := strconv.Atoi(attrs["from_port"])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error converting from_port in Security Group migration")
|
||||
}
|
||||
|
||||
perm.ToPort = aws.Long(int64(tp))
|
||||
perm.FromPort = aws.Long(int64(fp))
|
||||
perm.IPProtocol = aws.String(attrs["protocol"])
|
||||
|
||||
groups := make(map[string]bool)
|
||||
if attrs["self"] == "true" {
|
||||
groups[attrs["security_group_id"]] = true
|
||||
}
|
||||
|
||||
if attrs["source_security_group_id"] != "" {
|
||||
groups[attrs["source_security_group_id"]] = true
|
||||
}
|
||||
|
||||
if len(groups) > 0 {
|
||||
perm.UserIDGroupPairs = make([]*ec2.UserIDGroupPair, len(groups))
|
||||
// build string list of group name/ids
|
||||
var gl []string
|
||||
for k, _ := range groups {
|
||||
gl = append(gl, k)
|
||||
}
|
||||
|
||||
for i, name := range gl {
|
||||
perm.UserIDGroupPairs[i] = &ec2.UserIDGroupPair{
|
||||
GroupID: aws.String(name),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var cb []string
|
||||
for k, v := range attrs {
|
||||
if k != "cidr_blocks.#" && strings.HasPrefix(k, "cidr_blocks") {
|
||||
cb = append(cb, v)
|
||||
}
|
||||
}
|
||||
if len(cb) > 0 {
|
||||
perm.IPRanges = make([]*ec2.IPRange, len(cb))
|
||||
for i, v := range cb {
|
||||
perm.IPRanges[i] = &ec2.IPRange{CIDRIP: aws.String(v)}
|
||||
}
|
||||
}
|
||||
|
||||
return &perm, nil
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAWSSecurityGroupRuleMigrateState(t *testing.T) {
|
||||
cases := map[string]struct {
|
||||
StateVersion int
|
||||
ID string
|
||||
Attributes map[string]string
|
||||
Expected string
|
||||
Meta interface{}
|
||||
}{
|
||||
"v0_1": {
|
||||
StateVersion: 0,
|
||||
ID: "sg-4235098228",
|
||||
Attributes: map[string]string{
|
||||
"self": "false",
|
||||
"to_port": "0",
|
||||
"security_group_id": "sg-13877277",
|
||||
"cidr_blocks.#": "0",
|
||||
"type": "ingress",
|
||||
"protocol": "-1",
|
||||
"from_port": "0",
|
||||
"source_security_group_id": "sg-11877275",
|
||||
},
|
||||
Expected: "sg-3766347571",
|
||||
},
|
||||
"v0_2": {
|
||||
StateVersion: 0,
|
||||
ID: "sg-1021609891",
|
||||
Attributes: map[string]string{
|
||||
"security_group_id": "sg-0981746d",
|
||||
"from_port": "0",
|
||||
"to_port": "0",
|
||||
"type": "ingress",
|
||||
"self": "false",
|
||||
"protocol": "-1",
|
||||
"cidr_blocks.0": "172.16.1.0/24",
|
||||
"cidr_blocks.1": "172.16.2.0/24",
|
||||
"cidr_blocks.2": "172.16.3.0/24",
|
||||
"cidr_blocks.3": "172.16.4.0/24",
|
||||
"cidr_blocks.#": "4"},
|
||||
Expected: "sg-4100229787",
|
||||
},
|
||||
}
|
||||
|
||||
for tn, tc := range cases {
|
||||
is := &terraform.InstanceState{
|
||||
ID: tc.ID,
|
||||
Attributes: tc.Attributes,
|
||||
}
|
||||
is, err := resourceAwsSecurityGroupRuleMigrateState(
|
||||
tc.StateVersion, is, tc.Meta)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("bad: %s, err: %#v", tn, err)
|
||||
}
|
||||
|
||||
if is.ID != tc.Expected {
|
||||
t.Fatalf("bad sg rule id: %s\n\n expected: %s", is.ID, tc.Expected)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
|
@ -44,6 +45,46 @@ func TestIpPermissionIDHash(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
vpc_security_group_source := &ec2.IPPermission{
|
||||
IPProtocol: aws.String("tcp"),
|
||||
FromPort: aws.Long(int64(80)),
|
||||
ToPort: aws.Long(int64(8000)),
|
||||
UserIDGroupPairs: []*ec2.UserIDGroupPair{
|
||||
&ec2.UserIDGroupPair{
|
||||
UserID: aws.String("987654321"),
|
||||
GroupID: aws.String("sg-12345678"),
|
||||
},
|
||||
&ec2.UserIDGroupPair{
|
||||
UserID: aws.String("123456789"),
|
||||
GroupID: aws.String("sg-987654321"),
|
||||
},
|
||||
&ec2.UserIDGroupPair{
|
||||
UserID: aws.String("123456789"),
|
||||
GroupID: aws.String("sg-12345678"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
security_group_source := &ec2.IPPermission{
|
||||
IPProtocol: aws.String("tcp"),
|
||||
FromPort: aws.Long(int64(80)),
|
||||
ToPort: aws.Long(int64(8000)),
|
||||
UserIDGroupPairs: []*ec2.UserIDGroupPair{
|
||||
&ec2.UserIDGroupPair{
|
||||
UserID: aws.String("987654321"),
|
||||
GroupName: aws.String("my-security-group"),
|
||||
},
|
||||
&ec2.UserIDGroupPair{
|
||||
UserID: aws.String("123456789"),
|
||||
GroupName: aws.String("my-security-group"),
|
||||
},
|
||||
&ec2.UserIDGroupPair{
|
||||
UserID: aws.String("123456789"),
|
||||
GroupName: aws.String("my-other-security-group"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// hardcoded hashes, to detect future change
|
||||
cases := []struct {
|
||||
Input *ec2.IPPermission
|
||||
|
@ -52,13 +93,15 @@ func TestIpPermissionIDHash(t *testing.T) {
|
|||
}{
|
||||
{simple, "ingress", "sg-82613597"},
|
||||
{egress, "egress", "sg-363054720"},
|
||||
{egress_all, "egress", "sg-857124156"},
|
||||
{egress_all, "egress", "sg-2766285362"},
|
||||
{vpc_security_group_source, "egress", "sg-2661404947"},
|
||||
{security_group_source, "egress", "sg-1841245863"},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
actual := ipPermissionIDHash(tc.Type, tc.Input)
|
||||
if actual != tc.Output {
|
||||
t.Fatalf("input: %s - %#v\noutput: %s", tc.Type, tc.Input, actual)
|
||||
t.Errorf("input: %s - %s\noutput: %s", tc.Type, awsutil.StringValue(tc.Input), actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -141,9 +184,9 @@ func TestAccAWSSecurityGroupRule_MultiIngress(t *testing.T) {
|
|||
var group ec2.SecurityGroup
|
||||
|
||||
testMultiRuleCount := func(*terraform.State) error {
|
||||
if len(group.IPPermissions) != 3 {
|
||||
if len(group.IPPermissions) != 2 {
|
||||
return fmt.Errorf("Wrong Security Group rule count, expected %d, got %d",
|
||||
3, len(group.IPPermissions))
|
||||
2, len(group.IPPermissions))
|
||||
}
|
||||
|
||||
var rule *ec2.IPPermission
|
||||
|
@ -395,7 +438,6 @@ resource "aws_security_group_rule" "ingress_1" {
|
|||
cidr_blocks = ["10.0.0.0/8"]
|
||||
|
||||
security_group_id = "${aws_security_group.web.id}"
|
||||
source_security_group_id = "${aws_security_group.worker.id}"
|
||||
}
|
||||
|
||||
resource "aws_security_group_rule" "ingress_2" {
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
"github.com/Azure/azure-sdk-for-go/management/affinitygroup"
|
||||
"github.com/Azure/azure-sdk-for-go/management/hostedservice"
|
||||
"github.com/Azure/azure-sdk-for-go/management/networksecuritygroup"
|
||||
"github.com/Azure/azure-sdk-for-go/management/osimage"
|
||||
|
@ -31,13 +32,15 @@ type Config struct {
|
|||
type Client struct {
|
||||
mgmtClient management.Client
|
||||
|
||||
affinityGroupClient affinitygroup.AffinityGroupClient
|
||||
|
||||
hostedServiceClient hostedservice.HostedServiceClient
|
||||
|
||||
secGroupClient networksecuritygroup.SecurityGroupClient
|
||||
|
||||
osImageClient osimage.OSImageClient
|
||||
|
||||
sqlClient sql.SqlDatabaseClient
|
||||
sqlClient sql.SQLDatabaseClient
|
||||
|
||||
storageServiceClient storageservice.StorageServiceClient
|
||||
|
||||
|
@ -107,6 +110,7 @@ func (c *Config) NewClientFromSettingsFile() (*Client, error) {
|
|||
|
||||
return &Client{
|
||||
mgmtClient: mc,
|
||||
affinityGroupClient: affinitygroup.NewClient(mc),
|
||||
hostedServiceClient: hostedservice.NewClient(mc),
|
||||
secGroupClient: networksecuritygroup.NewClient(mc),
|
||||
osImageClient: osimage.NewClient(mc),
|
||||
|
@ -130,6 +134,7 @@ func (c *Config) NewClient() (*Client, error) {
|
|||
|
||||
return &Client{
|
||||
mgmtClient: mc,
|
||||
affinityGroupClient: affinitygroup.NewClient(mc),
|
||||
hostedServiceClient: hostedservice.NewClient(mc),
|
||||
secGroupClient: networksecuritygroup.NewClient(mc),
|
||||
osImageClient: osimage.NewClient(mc),
|
||||
|
|
|
@ -33,6 +33,7 @@ func Provider() terraform.ResourceProvider {
|
|||
|
||||
ResourcesMap: map[string]*schema.Resource{
|
||||
"azure_instance": resourceAzureInstance(),
|
||||
"azure_affinity_group": resourceAzureAffinityGroup(),
|
||||
"azure_data_disk": resourceAzureDataDisk(),
|
||||
"azure_sql_database_server": resourceAzureSqlDatabaseServer(),
|
||||
"azure_sql_database_service": resourceAzureSqlDatabaseService(),
|
||||
|
|
|
@ -0,0 +1,168 @@
|
|||
package azure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
"github.com/Azure/azure-sdk-for-go/management/affinitygroup"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
// resourceAzureAffinityGroup returns the *schema.Resource associated to a
|
||||
// resource affinity group on Azure.
|
||||
func resourceAzureAffinityGroup() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceAzureAffinityGroupCreate,
|
||||
Read: resourceAzureAffinityGroupRead,
|
||||
Update: resourceAzureAffinityGroupUpdate,
|
||||
Exists: resourceAzureAffinityGroupExists,
|
||||
Delete: resourceAzureAffinityGroupDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"location": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"label": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"description": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// resourceAzureAffinityGroupCreate does all the necessary API calls to
|
||||
// create an affinity group on Azure.
|
||||
func resourceAzureAffinityGroupCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
affinityGroupClient := meta.(*Client).affinityGroupClient
|
||||
|
||||
log.Println("[INFO] Begun creating Azure Affinity Group creation request.")
|
||||
name := d.Get("name").(string)
|
||||
params := affinitygroup.CreateAffinityGroupParams{
|
||||
Name: name,
|
||||
Label: d.Get("label").(string),
|
||||
Location: d.Get("location").(string),
|
||||
}
|
||||
|
||||
if desc, ok := d.GetOk("description"); ok {
|
||||
params.Description = desc.(string)
|
||||
}
|
||||
|
||||
log.Println("[INFO] Sending Affinity Group creation request to Azure.")
|
||||
err := affinityGroupClient.CreateAffinityGroup(params)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error issuing Azure Affinity Group creation: %s", err)
|
||||
}
|
||||
|
||||
d.SetId(name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// resourceAzureAffinityGroupRead does all the necessary API calls to
|
||||
// read the state of the affinity group off Azure.
|
||||
func resourceAzureAffinityGroupRead(d *schema.ResourceData, meta interface{}) error {
|
||||
affinityGroupClient := meta.(*Client).affinityGroupClient
|
||||
|
||||
log.Println("[INFO] Issuing Azure Affinity Group list request.")
|
||||
affinityGroups, err := affinityGroupClient.ListAffinityGroups()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error obtaining Affinity Group list off Azure: %s", err)
|
||||
}
|
||||
|
||||
var found bool
|
||||
name := d.Get("name").(string)
|
||||
for _, group := range affinityGroups.AffinityGroups {
|
||||
if group.Name == name {
|
||||
found = true
|
||||
d.Set("location", group.Location)
|
||||
d.Set("label", group.Label)
|
||||
d.Set("description", group.Description)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
// it means the affinity group has been deleted in the meantime, so we
|
||||
// must stop tracking it:
|
||||
d.SetId("")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// resourceAzureAffinityGroupUpdate does all the necessary API calls to
|
||||
// update the state of the affinity group on Azure.
|
||||
func resourceAzureAffinityGroupUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
affinityGroupClient := meta.(*Client).affinityGroupClient
|
||||
|
||||
name := d.Get("name").(string)
|
||||
clabel := d.HasChange("label")
|
||||
cdesc := d.HasChange("description")
|
||||
if clabel || cdesc {
|
||||
log.Println("[INFO] Beginning Affinity Group update process.")
|
||||
params := affinitygroup.UpdateAffinityGroupParams{}
|
||||
|
||||
if clabel {
|
||||
params.Label = d.Get("label").(string)
|
||||
}
|
||||
if cdesc {
|
||||
params.Description = d.Get("description").(string)
|
||||
}
|
||||
|
||||
log.Println("[INFO] Sending Affinity Group update request to Azure.")
|
||||
err := affinityGroupClient.UpdateAffinityGroup(name, params)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating Azure Affinity Group parameters: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// resourceAzureAffinityGroupExists does all the necessary API calls to
|
||||
// check for the existence of the affinity group on Azure.
|
||||
func resourceAzureAffinityGroupExists(d *schema.ResourceData, meta interface{}) (bool, error) {
|
||||
affinityGroupClient := meta.(*Client).affinityGroupClient
|
||||
|
||||
log.Println("[INFO] Issuing Azure Affinity Group get request.")
|
||||
name := d.Get("name").(string)
|
||||
_, err := affinityGroupClient.GetAffinityGroup(name)
|
||||
if err != nil {
|
||||
if management.IsResourceNotFoundError(err) {
|
||||
// it means that the affinity group has been deleted in the
|
||||
// meantime, so we must untrack it from the schema:
|
||||
d.SetId("")
|
||||
return false, nil
|
||||
} else {
|
||||
return false, fmt.Errorf("Error getting Affinity Group off Azure: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// resourceAzureAffinityGroupDelete does all the necessary API calls to
|
||||
// delete the affinity group off Azure.
|
||||
func resourceAzureAffinityGroupDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
affinityGroupClient := meta.(*Client).affinityGroupClient
|
||||
|
||||
log.Println("[INFO] Sending Affinity Group deletion request to Azure.")
|
||||
name := d.Get("name").(string)
|
||||
err := affinityGroupClient.DeleteAffinityGroup(name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting Azure Affinity Group: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
package azure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/management"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccAzureAffinityGroupBasic(t *testing.T) {
|
||||
name := "azure_affinity_group.foo"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAzureAffinityGroupDestroyed,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAzureAffinityGroupConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAzureAffinityGroupExists(name),
|
||||
resource.TestCheckResourceAttr(name, "name", "terraform-testing-group"),
|
||||
resource.TestCheckResourceAttr(name, "location", "West US"),
|
||||
resource.TestCheckResourceAttr(name, "label", "A nice label."),
|
||||
resource.TestCheckResourceAttr(name, "description", "A nice description."),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAzureAffinityGroupUpdate(t *testing.T) {
|
||||
name := "azure_affinity_group.foo"
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAzureAffinityGroupDestroyed,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAzureAffinityGroupConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAzureAffinityGroupExists(name),
|
||||
resource.TestCheckResourceAttr(name, "name", "terraform-testing-group"),
|
||||
resource.TestCheckResourceAttr(name, "location", "West US"),
|
||||
resource.TestCheckResourceAttr(name, "label", "A nice label."),
|
||||
resource.TestCheckResourceAttr(name, "description", "A nice description."),
|
||||
),
|
||||
},
|
||||
resource.TestStep{
|
||||
Config: testAccAzureAffinityGroupUpdateConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAzureAffinityGroupExists(name),
|
||||
resource.TestCheckResourceAttr(name, "name", "terraform-testing-group"),
|
||||
resource.TestCheckResourceAttr(name, "location", "West US"),
|
||||
resource.TestCheckResourceAttr(name, "label", "An even nicer label."),
|
||||
resource.TestCheckResourceAttr(name, "description", "An even nicer description."),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckAzureAffinityGroupExists(name string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
resource, ok := s.RootModule().Resources[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("Affinity Group resource %q doesn't exist.", name)
|
||||
}
|
||||
|
||||
if resource.Primary.ID == "" {
|
||||
return fmt.Errorf("Affinity Group resource %q ID not set.", name)
|
||||
}
|
||||
|
||||
affinityGroupClient := testAccProvider.Meta().(*Client).affinityGroupClient
|
||||
_, err := affinityGroupClient.GetAffinityGroup(resource.Primary.ID)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckAzureAffinityGroupDestroyed(s *terraform.State) error {
|
||||
var err error
|
||||
affinityGroupClient := testAccProvider.Meta().(*Client).affinityGroupClient
|
||||
|
||||
for _, resource := range s.RootModule().Resources {
|
||||
if resource.Type != "azure_affinity_group" {
|
||||
continue
|
||||
}
|
||||
|
||||
if resource.Primary.ID == "" {
|
||||
return fmt.Errorf("Affinity Group resource ID not set.")
|
||||
}
|
||||
|
||||
_, err = affinityGroupClient.GetAffinityGroup(resource.Primary.ID)
|
||||
if !management.IsResourceNotFoundError(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
const testAccAzureAffinityGroupConfig = `
|
||||
resource "azure_affinity_group" "foo" {
|
||||
name = "terraform-testing-group"
|
||||
location = "West US"
|
||||
label = "A nice label."
|
||||
description = "A nice description."
|
||||
}
|
||||
`
|
||||
|
||||
const testAccAzureAffinityGroupUpdateConfig = `
|
||||
resource "azure_affinity_group" "foo" {
|
||||
name = "terraform-testing-group"
|
||||
location = "West US"
|
||||
label = "An even nicer label."
|
||||
description = "An even nicer description."
|
||||
}
|
||||
`
|
|
@ -0,0 +1,53 @@
|
|||
---
|
||||
layout: "aws"
|
||||
page_title: "AWS: aws_autoscaling_policy"
|
||||
sidebar_current: "docs-aws-resource-autoscaling-policy"
|
||||
description: |-
|
||||
Provides an AutoScaling Scaling Group resource.
|
||||
---
|
||||
|
||||
# aws\_autoscaling\_policy
|
||||
|
||||
Provides an AutoScaling Scaling Policy resource.
|
||||
|
||||
~> **NOTE:** You may want to omit `desired_capacity` attribute from attached `aws_autoscaling_group`
|
||||
when using autoscaling policies. It's good practice to pick either
|
||||
[manual](http://docs.aws.amazon.com/AutoScaling/latest/DeveloperGuide/as-manual-scaling.html)
|
||||
or [dynamic](http://docs.aws.amazon.com/AutoScaling/latest/DeveloperGuide/as-scale-based-on-demand.html)
|
||||
(policy-based) scaling.
|
||||
|
||||
## Example Usage
|
||||
```
|
||||
resource "aws_autoscaling_policy" "bat" {
|
||||
name = "foobar3-terraform-test"
|
||||
scaling_adjustment = 4
|
||||
adjustment_type = "ChangeInCapacity"
|
||||
cooldown = 300
|
||||
autoscaling_group_name = "${aws_autoscaling_group.bar.name}"
|
||||
}
|
||||
|
||||
resource "aws_autoscaling_group" "bar" {
|
||||
availability_zones = ["us-east-1a"]
|
||||
name = "foobar3-terraform-test"
|
||||
max_size = 5
|
||||
min_size = 2
|
||||
health_check_grace_period = 300
|
||||
health_check_type = "ELB"
|
||||
force_delete = true
|
||||
launch_configuration = "${aws_launch_configuration.foo.name}"
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) The name of the policy.
|
||||
* `autoscaling_group_name` - (Required) The name or ARN of the group.
|
||||
* `adjustment_type` - (Required) Specifies whether the `scaling_adjustment` is an absolute number or a percentage of the current capacity. Valid values are `ChangeInCapacity`, `ExactCapacity`, and `PercentChangeInCapacity`.
|
||||
* `scaling_adjustment` - (Required) The number of instances by which to scale. `adjustment_type` determines the interpretation of this number (e.g., as an absolute number or as a percentage of the existing Auto Scaling group size). A positive increment adds to the current capacity and a negative value removes from the current capacity.
|
||||
* `cooldown` - (Optional) The amount of time, in seconds, after a scaling activity completes and before the next scaling activity can start.
|
||||
* `min_adjustment_step` - (Optional) Used with `adjustment_type` with the value `PercentChangeInCapacity`, the scaling policy changes the `desired_capacity` of the Auto Scaling group by at least the number of instances specified in the value.
|
||||
|
||||
## Attribute Reference
|
||||
* `arn` - The ARN assigned by AWS to the scaling policy.
|
|
@ -0,0 +1,75 @@
|
|||
---
|
||||
layout: "aws"
|
||||
page_title: "AWS: cloudwatch_metric_alarm"
|
||||
sidebar_current: "docs-aws-resource-cloudwatch-metric-alarm"
|
||||
description: |-
|
||||
Provides an AutoScaling Scaling Group resource.
|
||||
---
|
||||
|
||||
# aws\_cloudwatch\_metric\_alarm
|
||||
|
||||
Provides a CloudWatch Metric Alarm resource.
|
||||
|
||||
## Example Usage
|
||||
```
|
||||
resource "aws_cloudwatch_metric_alarm" "foobar" {
|
||||
alarm_name = "terraform-test-foobar5"
|
||||
comparison_operator = "GreaterThanOrEqualToThreshold"
|
||||
evaluation_periods = "2"
|
||||
metric_name = "CPUUtilization"
|
||||
namespace = "AWS/EC2"
|
||||
period = "120"
|
||||
statistic = "Average"
|
||||
threshold = "80"
|
||||
alarm_description = "This metric monitor ec2 cpu utilization"
|
||||
insufficient_data_actions = []
|
||||
}
|
||||
```
|
||||
|
||||
## Example in Conjuction with Scaling Policies
|
||||
```
|
||||
resource "aws_autoscaling_policy" "bat" {
|
||||
name = "foobar3-terraform-test"
|
||||
scaling_adjustment = 4
|
||||
adjustment_type = "ChangeInCapacity"
|
||||
cooldown = 300
|
||||
autoscaling_group_name = "${aws_autoscaling_group.bar.name}"
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_metric_alarm" "bat" {
|
||||
alarm_name = "terraform-test-foobar5"
|
||||
comparison_operator = "GreaterThanOrEqualToThreshold"
|
||||
evaluation_periods = "2"
|
||||
metric_name = "CPUUtilization"
|
||||
namespace = "AWS/EC2"
|
||||
period = "120"
|
||||
statistic = "Average"
|
||||
threshold = "80"
|
||||
alarm_description = "This metric monitor ec2 cpu utilization"
|
||||
alarm_actions = ["${aws_autoscaling_policy.bat.arn}"]
|
||||
}
|
||||
```
|
||||
## Argument Reference
|
||||
|
||||
See [related part of AWS Docs](http://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_PutMetricAlarm.html)
|
||||
for details about valid values.
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `alarm_name` - (Required) The descriptive name for the alarm. This name must be unique within the user's AWS account
|
||||
* `comparison_operator` - (Required) The arithmetic operation to use when comparing the specified Statistic and Threshold. The specified Statistic value is used as the first operand. Either of the following is supported: `GreaterThanOrEqualToThreshold`, `GreaterThanThreshold`, `LessThanThreshold`, `LessThanOrEqualToThreshold`.
|
||||
* `evaluation_periods` - (Required) The number of periods over which data is compared to the specified threshold.
|
||||
* `metric_name` - (Required) The name for the alarm's associated metric.
|
||||
See docs for [supported metrics]([valid metrics](http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/CW_Support_For_AWS.html)).
|
||||
* `namespace` - (Required) The namespace for the alarm's associated metric.
|
||||
* `period` - (Required) The period in seconds over which the specified `statistic` is applied.
|
||||
* `statistic` - (Required) The statistic to apply to the alarm's associated metric.
|
||||
Either of the following is supported: `SampleCount`, `Average`, `Sum`, `Minimum`, `Maximum`
|
||||
* `threshold` - (Required) The value against which the specified statistic is compared.
|
||||
* `actions_enabled` - (Optional) Indicates whether or not actions should be executed during any changes to the alarm's state. Defaults to `true`.
|
||||
* `alarm_actions` - (Optional) The list of actions to execute when this alarm transitions into an ALARM state from any other state. Each action is specified as an Amazon Resource Number (ARN).
|
||||
* `alarm_description` - (Optional) The description for the alarm.
|
||||
* `dimensions` - (Optional) The dimensions for the alarm's associated metric.
|
||||
* `insufficient_data_actions` - (Optional) The list of actions to execute when this alarm transitions into an INSUFFICIENT_DATA state from any other state. Each action is specified as an Amazon Resource Number (ARN).
|
||||
* `ok_actions` - (Optional) The list of actions to execute when this alarm transitions into an OK state from any other state. Each action is specified as an Amazon Resource Number (ARN).
|
||||
* `unit` - (Optional) The unit for the alarm's associated metric.
|
|
@ -0,0 +1,42 @@
|
|||
---
|
||||
layout: "azure"
|
||||
page_title: "Azure: azure_affinity_group"
|
||||
sidebar_current: "docs-azure-affinity-group"
|
||||
description: |-
|
||||
Creates a new affinity group on Azure.
|
||||
---
|
||||
|
||||
# azure\_affinity\_group
|
||||
|
||||
Creates a new affinity group on Azure.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
resource "azure_affinity_group" "terraform-main-group" {
|
||||
name = "terraform-group"
|
||||
location = "North Europe"
|
||||
label = "tf-group-01"
|
||||
description = "Affinity group created by Terraform."
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) The name of the affinity group. Must be unique on your
|
||||
Azure subscription.
|
||||
|
||||
* `location` - (Required) The location where the affinity group should be created.
|
||||
For a list of all Azure locations, please consult [this link](http://azure.microsoft.com/en-us/regions/).
|
||||
|
||||
* `label` - (Required) A label to be used for tracking purposes.
|
||||
|
||||
* `description` - (Optional) A description for the affinity group.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `id` - The affinity group ID. Coincides with the given `name`.
|
|
@ -21,6 +21,14 @@
|
|||
<a href="/docs/providers/aws/r/autoscaling_notification.html">aws_autoscaling_notification</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-aws-resource-autoscaling-policy") %>>
|
||||
<a href="/docs/providers/aws/r/autoscaling_policy.html">aws_autoscaling_policy</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-aws-resource-cloudwatch-metric-alarm") %>>
|
||||
<a href="/docs/providers/aws/r/cloudwatch_metric_alarm.html">aws_cloudwatch_metric_alarm</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-aws-resource-customer-gateway") %>>
|
||||
<a href="/docs/providers/aws/r/customer_gateway.html">aws_customer_gateway</a>
|
||||
</li>
|
||||
|
|
|
@ -13,6 +13,10 @@
|
|||
<li<%= sidebar_current(/^docs-azure-resource/) %>>
|
||||
<a href="#">Resources</a>
|
||||
<ul class="nav nav-visible">
|
||||
<li<%= sidebar_current("docs-azure-resource-affinity-group") %>>
|
||||
<a href="/docs/providers/azure/r/affinity_group.html">azure_affinity_group</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-azure-resource-data-disk") %>>
|
||||
<a href="/docs/providers/azure/r/data_disk.html">azure_data_disk</a>
|
||||
</li>
|
||||
|
|
Loading…
Reference in New Issue