chef-provisioning-aws 1.9.0 → 1.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -4
  3. data/lib/chef/provider/aws_auto_scaling_group.rb +15 -1
  4. data/lib/chef/provider/aws_cloudwatch_alarm.rb +84 -0
  5. data/lib/chef/provider/aws_ebs_volume.rb +1 -1
  6. data/lib/chef/provider/aws_image.rb +13 -5
  7. data/lib/chef/provider/aws_launch_configuration.rb +4 -4
  8. data/lib/chef/provider/aws_nat_gateway.rb +57 -0
  9. data/lib/chef/provider/aws_network_interface.rb +1 -1
  10. data/lib/chef/provider/aws_route_table.rb +7 -3
  11. data/lib/chef/provider/aws_vpc.rb +20 -0
  12. data/lib/chef/provisioning/aws_driver.rb +2 -0
  13. data/lib/chef/provisioning/aws_driver/aws_provider.rb +1 -1
  14. data/lib/chef/provisioning/aws_driver/driver.rb +10 -5
  15. data/lib/chef/provisioning/aws_driver/tagging_strategy/auto_scaling.rb +76 -0
  16. data/lib/chef/provisioning/aws_driver/version.rb +1 -1
  17. data/lib/chef/resource/aws_auto_scaling_group.rb +12 -8
  18. data/lib/chef/resource/aws_cloudwatch_alarm.rb +35 -0
  19. data/lib/chef/resource/aws_image.rb +4 -4
  20. data/lib/chef/resource/aws_launch_configuration.rb +1 -1
  21. data/lib/chef/resource/aws_nat_gateway.rb +98 -0
  22. data/lib/chef/resource/aws_route_table.rb +1 -0
  23. data/spec/aws_support.rb +1 -1
  24. data/spec/integration/aws_auto_scaling_group_spec.rb +118 -0
  25. data/spec/integration/aws_cloudwatch_alarm_spec.rb +286 -0
  26. data/spec/integration/aws_nat_gateway_spec.rb +52 -0
  27. data/spec/integration/aws_rds_instance_spec.rb +10 -10
  28. data/spec/integration/aws_route_table_spec.rb +22 -0
  29. data/spec/integration/aws_vpc_spec.rb +31 -3
  30. data/spec/spec_helper.rb +4 -2
  31. metadata +11 -3
@@ -0,0 +1,76 @@
1
+ require 'chef/provisioning/aws_driver/aws_tagger'
2
+
3
+ module Chef::Provisioning::AWSDriver::TaggingStrategy
4
+ module AutoScalingConvergeTags
5
+ def aws_tagger
6
+ @aws_tagger ||= begin
7
+ auto_scaling_strategy = Chef::Provisioning::AWSDriver::TaggingStrategy::AutoScaling.new(
8
+ new_resource.driver.auto_scaling_client,
9
+ new_resource.name,
10
+ new_resource.aws_tags
11
+ )
12
+ Chef::Provisioning::AWSDriver::AWSTagger.new(auto_scaling_strategy, action_handler)
13
+ end
14
+ end
15
+ def converge_tags
16
+ aws_tagger.converge_tags
17
+ end
18
+ end
19
+ end
20
+
21
+ module Chef::Provisioning::AWSDriver::TaggingStrategy
22
+ class AutoScaling
23
+
24
+ attr_reader :auto_scaling_client, :group_name, :desired_tags
25
+
26
+ def initialize(auto_scaling_client, group_name, desired_tags)
27
+ @auto_scaling_client = auto_scaling_client
28
+ @group_name = group_name
29
+ @desired_tags = desired_tags
30
+ end
31
+
32
+ def current_tags
33
+ # http://docs.aws.amazon.com/sdkforruby/api/Aws/AutoScaling/Client.html#describe_tags-instance_method
34
+ resp = auto_scaling_client.describe_tags({
35
+ filters: [
36
+ {
37
+ name: "auto-scaling-group",
38
+ values: [group_name]
39
+ }
40
+ ]
41
+ })
42
+ Hash[resp.tags.map {|t| [t.key, t.value]}]
43
+ end
44
+
45
+ def set_tags(tags)
46
+ # http://docs.aws.amazon.com/sdkforruby/api/Aws/AutoScaling/Client.html#create_or_update_tags-instance_method
47
+ auto_scaling_client.create_or_update_tags({
48
+ tags: tags.map {|k,v|
49
+ {
50
+ resource_id: group_name,
51
+ key: k,
52
+ value: v,
53
+ resource_type: "auto-scaling-group",
54
+ propagate_at_launch: false
55
+ }
56
+ }
57
+ })
58
+ end
59
+
60
+ def delete_tags(tag_keys)
61
+ # http://docs.aws.amazon.com/sdkforruby/api/Aws/AutoScaling/Client.html#delete_tags-instance_method
62
+ auto_scaling_client.delete_tags({
63
+ tags: tag_keys.map {|k|
64
+ {
65
+ resource_id: group_name,
66
+ key: k,
67
+ value: nil,
68
+ resource_type: "auto-scaling-group",
69
+ propagate_at_launch: false
70
+ }
71
+ }
72
+ })
73
+ end
74
+
75
+ end
76
+ end
@@ -1,7 +1,7 @@
1
1
  class Chef
2
2
  module Provisioning
3
3
  module AWSDriver
4
- VERSION = '1.9.0'
4
+ VERSION = '1.10.0'
5
5
  end
6
6
  end
7
7
  end
@@ -1,16 +1,20 @@
1
1
  require 'chef/provisioning/aws_driver/aws_resource'
2
2
 
3
3
  class Chef::Resource::AwsAutoScalingGroup < Chef::Provisioning::AWSDriver::AWSResource
4
+ include Chef::Provisioning::AWSDriver::AWSTaggable
5
+
4
6
  aws_sdk_type AWS::AutoScaling::Group
5
7
 
6
- attribute :name, kind_of: String, name_attribute: true
7
- attribute :options, kind_of: Hash, default: {}
8
- attribute :availability_zones, kind_of: Array
9
- attribute :desired_capacity, kind_of: Integer
10
- attribute :launch_configuration, kind_of: String
11
- attribute :min_size, kind_of: Integer
12
- attribute :max_size, kind_of: Integer
13
- attribute :load_balancers, kind_of: Array, coerce: proc { |value| [value].flatten }
8
+ attribute :name, kind_of: String, name_attribute: true
9
+ attribute :options, kind_of: Hash, default: {}
10
+ attribute :availability_zones, kind_of: Array
11
+ attribute :desired_capacity, kind_of: Integer
12
+ attribute :launch_configuration, kind_of: String
13
+ attribute :min_size, kind_of: Integer
14
+ attribute :max_size, kind_of: Integer
15
+ attribute :load_balancers, kind_of: Array, coerce: proc { |value| [value].flatten }
16
+ attribute :notification_configurations, kind_of: Array, default: []
17
+ attribute :scaling_policies, kind_of: Hash, default: {}
14
18
 
15
19
  def aws_object
16
20
  result = driver.auto_scaling.groups[name]
@@ -0,0 +1,35 @@
1
+ require 'chef/provisioning/aws_driver/aws_resource'
2
+
3
+ class Chef::Resource::AwsCloudwatchAlarm < Chef::Provisioning::AWSDriver::AWSResource
4
+ include Chef::Provisioning::AWSDriver::AWSTaggable
5
+
6
+ aws_sdk_type ::Aws::CloudWatch::Alarm, id: :name
7
+
8
+ # This name must be unique within the user's AWS account
9
+ attribute :name, :kind_of => String, :name_attribute => true
10
+ attribute :namespace, :kind_of => String
11
+ attribute :metric_name, :kind_of => String
12
+ attribute :dimensions, :kind_of => Array
13
+ attribute :comparison_operator, :kind_of => String
14
+ attribute :evaluation_periods, :kind_of => Integer
15
+ attribute :period, :kind_of => [Integer,Float], coerce: proc {|v| v.to_f}
16
+ attribute :statistic, :kind_of => String
17
+ attribute :threshold, :kind_of => Integer
18
+ attribute :insufficient_data_actions, :kind_of => Array, coerce: proc {|v| [v].flatten}
19
+ attribute :ok_actions, :kind_of => Array, coerce: proc {|v| [v].flatten}
20
+ attribute :alarm_actions, :kind_of => Array, coerce: proc {|v| [v].flatten}
21
+ attribute :actions_enabled, :kind_of => [TrueClass, FalseClass]
22
+ attribute :alarm_description, :kind_of => String
23
+ attribute :unit, :kind_of => String
24
+
25
+ def aws_object
26
+ # TODO exists? isn't defined yet
27
+ # https://github.com/aws/aws-sdk-ruby/issues/1171
28
+ a = driver.cloudwatch_resource.alarm(name)
29
+ return nil if a.data.nil?
30
+ a
31
+ rescue ::Aws::CloudWatch::Errors::NoSuchEntity
32
+ nil
33
+ end
34
+
35
+ end
@@ -4,11 +4,11 @@ require 'chef/provisioning/aws_driver/aws_taggable'
4
4
  class Chef::Resource::AwsImage < Chef::Provisioning::AWSDriver::AWSResourceWithEntry
5
5
  include Chef::Provisioning::AWSDriver::AWSTaggable
6
6
 
7
- aws_sdk_type AWS::EC2::Image,
8
- managed_entry_type: :machine_image,
7
+ aws_sdk_type ::Aws::EC2::Image,
8
+ managed_entry_type: :machine_image,
9
9
  managed_entry_id_name: 'image_id'
10
10
 
11
- attribute :name, kind_of: String, name_attribute: true
11
+ attribute :name, kind_of: String, name_attribute: true
12
12
 
13
13
  attribute :image_id, kind_of: String, aws_id_attribute: true, default: lazy {
14
14
  name =~ /^ami-[a-f0-9]{8}$/ ? name : nil
@@ -16,7 +16,7 @@ class Chef::Resource::AwsImage < Chef::Provisioning::AWSDriver::AWSResourceWithE
16
16
 
17
17
  def aws_object
18
18
  driver, id = get_driver_and_id
19
- result = driver.ec2.images[id] if id
19
+ result = driver.ec2_resource.image(id) if id
20
20
  result && result.exists? ? result : nil
21
21
  end
22
22
  end
@@ -4,7 +4,7 @@ class Chef::Resource::AwsLaunchConfiguration < Chef::Provisioning::AWSDriver::AW
4
4
  aws_sdk_type AWS::AutoScaling::LaunchConfiguration, id: :name
5
5
 
6
6
  attribute :name, kind_of: String, name_attribute: true
7
- attribute :image, kind_of: [ String, AWS::EC2::Image ]
7
+ attribute :image, kind_of: [ String, AWS::EC2::Image, ::Aws::EC2::Image ]
8
8
  attribute :instance_type, kind_of: String
9
9
  attribute :options, kind_of: Hash, default: {}
10
10
 
@@ -0,0 +1,98 @@
1
+ #
2
+ # An AWS nat gateway, enable instances in a private subnet to connect to
3
+ # the Internet or other AWS services, but prevent the Internet from
4
+ # initiating a connection with those instances
5
+ #
6
+ # `name` is not guaranteed unique for an AWS account; therefore, Chef will
7
+ # store the nat gateway ID associated with this name in your Chef server in the
8
+ # data bag `data/aws_nat_gateway/<name>`.
9
+ #
10
+ # API documentation for the AWS Ruby SDK for Nat gateway can be found here:
11
+ #
12
+ # - http://docs.aws.amazon.com/sdkforruby/api/Aws/EC2/Types/NatGateway.html
13
+ #
14
+
15
+ # We provide this class because the AWS SDK V2 does not provide it (as of
16
+ # May 2016). We copied the pattern in their SDK so when they do add a real
17
+ # resource there shouldn't be a need for much translation.
18
+ class Aws::EC2::NatGateway < Aws::Resources::Resource
19
+ attr_reader :resource, :id, :nat_gateway_id, :vpc_id, :subnet_id, :nat_gateway_addresses
20
+
21
+ def initialize(id, options = {})
22
+ @id = id
23
+ @nat_gateway_id = id
24
+ @client = options[:client]
25
+ nat_gateway_struct = get_nat_gateway_struct
26
+ @vpc_id = nat_gateway_struct.vpc_id
27
+ @subnet_id = nat_gateway_struct.subnet_id
28
+ @nat_gateway_addresses = nat_gateway_struct.nat_gateway_addresses
29
+ end
30
+
31
+ def state
32
+ get_nat_gateway_struct.state
33
+ end
34
+
35
+ def delete
36
+ @client.delete_nat_gateway({ nat_gateway_id: @id })
37
+ end
38
+
39
+ private
40
+ def get_nat_gateway_struct
41
+ @client.describe_nat_gateways({ nat_gateway_ids: [@id] }).nat_gateways.first
42
+ end
43
+ end
44
+
45
+ # See comment on class above as to why we add these methods to the AWS SDK
46
+ class Aws::EC2::Resource
47
+ def create_nat_gateway(options)
48
+ nat_gateway_struct = self.client.create_nat_gateway(options).nat_gateway
49
+ self.nat_gateway(nat_gateway_struct.nat_gateway_id)
50
+ end
51
+
52
+ def nat_gateway(nat_gateway_id)
53
+ ::Aws::EC2::NatGateway.new(nat_gateway_id, {client: client})
54
+ end
55
+ end
56
+
57
+ class Chef::Resource::AwsNatGateway < Chef::Provisioning::AWSDriver::AWSResourceWithEntry
58
+
59
+ aws_sdk_type ::Aws::EC2::NatGateway, id: :nat_gateway_id, managed_entry_id_name: 'nat_gateway_id'
60
+
61
+ require 'chef/resource/aws_subnet'
62
+ require 'chef/resource/aws_eip_address'
63
+
64
+ #
65
+ # The name of this nat gateway.
66
+ #
67
+ attribute :name, kind_of: String, name_attribute: true
68
+
69
+ #
70
+ # A subnet to attach to the internet gateway.
71
+ #
72
+ # May be one of:
73
+ # - The name of an `aws_subnet` Chef resource.
74
+ # - An actual `aws_subnet` resource.
75
+ # - An Aws `Subnet` object.
76
+ #
77
+ attribute :subnet, kind_of: [ String, AwsSubnet, ::Aws::EC2::Subnet ]
78
+
79
+ #
80
+ # A elastic ip address for the nat gateway.
81
+ #
82
+ # May be one of:
83
+ # - The name of an `aws_eip_address` Chef resource.
84
+ # - An actual `aws_eip_address` resource.
85
+ # - nil, meaning that no EIP exists yet and needs to be created.
86
+ #
87
+ attribute :eip_address, kind_of: [ String, AWS::EC2::ElasticIp, AwsEipAddress, nil ], default: nil
88
+
89
+ attribute :nat_gateway_id, kind_of: String, aws_id_attribute: true, default: lazy {
90
+ name =~ /^nat-[A-Fa-f0-9]{17}$/ ? name : nil
91
+ }
92
+
93
+ def aws_object
94
+ driver, nat_gateway_id = get_driver_and_id
95
+ result = driver.ec2_resource.nat_gateway(nat_gateway_id) if nat_gateway_id
96
+ result && result.id ? result : nil
97
+ end
98
+ end
@@ -62,6 +62,7 @@ class Chef::Resource::AwsRouteTable < Chef::Provisioning::AWSDriver::AWSResource
62
62
  # The destination (the left side of the `=>`) is always a CIDR block.
63
63
  # The target (the right side of the `=>`) can be one of several things:
64
64
  # - { internet_gateway: <AWS Internet Gateway ID or object> }
65
+ # - { nat_gateway: <AWS Nat Gateway ID or object> }
65
66
  # - { instance: <Chef machine name or resource, AWS Instance ID or object> }
66
67
  # - { network_interface: <AWS Network Interface ID or object> }
67
68
  # - { vpc_peering_connection: <AWS VPC Peering Connection ID or object> }
data/spec/aws_support.rb CHANGED
@@ -23,7 +23,7 @@ module AWSSupport
23
23
  require 'aws'
24
24
  require 'aws_support/deep_matcher/matchable_object'
25
25
  require 'aws_support/deep_matcher/matchable_array'
26
- DeepMatcher::MatchableObject.matchable_classes << proc { |o| o.class.name =~ /^(AWS|Aws)::(EC2|ELB|IAM|S3|RDS|CloudSearch|Route53|ElasticsearchService)($|::)/ }
26
+ DeepMatcher::MatchableObject.matchable_classes << proc { |o| o.class.name =~ /^(AWS|Aws)::(AutoScaling|EC2|ELB|IAM|S3|RDS|CloudSearch|CloudWatch|Route53|ElasticsearchService)($|::)/ }
27
27
  DeepMatcher::MatchableArray.matchable_classes << AWS::Core::Data::List
28
28
 
29
29
  def purge_all
@@ -0,0 +1,118 @@
1
+ require 'spec_helper'
2
+
3
+ describe Chef::Resource::AwsAutoScalingGroup do
4
+ extend AWSSupport
5
+
6
+ when_the_chef_12_server 'exists', organization: 'foo', server_scope: :context do
7
+ with_aws 'When connected to AWS' do
8
+ # Select an amazon linux ami based upon region
9
+ ami = {
10
+ 'eu-west-1' => 'ami-3850624c',
11
+ 'eu-central-1' => 'ami-993383ea',
12
+ 'us-east-1' => 'ami-e024bf89',
13
+ 'us-west-1' => 'ami-951945d0',
14
+ 'us-west-2' => 'ami-16fd7026',
15
+ 'ap-northeast-1' => 'ami-dcfa4edd',
16
+ 'ap-northeast-2' => 'ami-7308c51d',
17
+ 'ap-southeast-1' => 'ami-74dda626',
18
+ 'ap-southeast-2' => 'ami-b5990e8f',
19
+ 'sa-east-1' => 'ami-3e3be423'
20
+ }[driver.aws_config.region]
21
+
22
+ aws_launch_configuration 'test_config' do
23
+ image ami
24
+ instance_type 't1.micro'
25
+ end
26
+
27
+ aws_sns_topic 'test_topic'
28
+
29
+ it "aws_auto_scaling_group 'test_group' creates an auto scaling group" do
30
+ expect_recipe {
31
+ aws_auto_scaling_group 'test_group' do
32
+ launch_configuration 'test_config'
33
+ availability_zones ["#{driver.aws_config.region}a"]
34
+ min_size 1
35
+ max_size 2
36
+ end
37
+ }.to create_an_aws_auto_scaling_group(
38
+ 'test_group').and be_idempotent
39
+ end
40
+
41
+ it "aws_auto_scaling_group 'test_group_with_policy' creates an auto scaling group" do
42
+ expect_recipe {
43
+ aws_auto_scaling_group 'test_group_with_policy' do
44
+ launch_configuration 'test_config'
45
+ availability_zones ["#{driver.aws_config.region}a"]
46
+ min_size 1
47
+ max_size 2
48
+ notification_configurations [{
49
+ topic: driver.build_arn(service: 'sns', resource: 'test_topic'),
50
+ types: [
51
+ 'autoscaling:EC2_INSTANCE_LAUNCH',
52
+ 'autoscaling:EC2_INSTANCE_TERMINATE'
53
+ ]
54
+ }]
55
+ scaling_policies(
56
+ test_policy: {
57
+ adjustment_type: 'ChangeInCapacity',
58
+ scaling_adjustment: 1
59
+ }
60
+ )
61
+ end
62
+ }.to create_an_aws_auto_scaling_group(
63
+ 'test_group_with_policy').and be_idempotent
64
+ end
65
+
66
+ it "creates aws_auto_scaling_group tags" do
67
+ expect_recipe {
68
+ aws_auto_scaling_group 'test_group_with_policy' do
69
+ launch_configuration 'test_config'
70
+ availability_zones ["#{driver.aws_config.region}a"]
71
+ min_size 1
72
+ max_size 2
73
+ aws_tags key1: "value"
74
+ end
75
+ }.to create_an_aws_auto_scaling_group('test_group_with_policy'
76
+ ).and have_aws_auto_scaling_group_tags('test_group_with_policy',
77
+ {
78
+ 'key1' => 'value'
79
+ }
80
+ ).and be_idempotent
81
+ end
82
+
83
+ context "with existing tags" do
84
+ aws_auto_scaling_group 'test_group_with_policy' do
85
+ launch_configuration 'test_config'
86
+ availability_zones ["#{driver.aws_config.region}a"]
87
+ min_size 1
88
+ max_size 2
89
+ aws_tags key1: "value"
90
+ end
91
+
92
+ it "updates aws_auto_scaling_group tags" do
93
+ expect_recipe {
94
+ aws_auto_scaling_group 'test_group_with_policy' do
95
+ aws_tags key1: "value2", key2: nil
96
+ end
97
+ }.to have_aws_auto_scaling_group_tags('test_group_with_policy',
98
+ {
99
+ 'key1' => 'value2',
100
+ 'key2' => ''
101
+ }
102
+ ).and be_idempotent
103
+ end
104
+
105
+ it "removes all aws_network_acl tags" do
106
+ expect_recipe {
107
+ aws_auto_scaling_group 'test_group_with_policy' do
108
+ aws_tags({})
109
+ end
110
+ }.to have_aws_auto_scaling_group_tags('test_group_with_policy',
111
+ {}
112
+ ).and be_idempotent
113
+ end
114
+ end
115
+
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,286 @@
1
+ require 'spec_helper'
2
+
3
+ describe Chef::Resource::AwsCloudwatchAlarm do
4
+ extend AWSSupport
5
+
6
+ when_the_chef_12_server 'exists', organization: 'foo', server_scope: :context do
7
+ with_aws 'When connected to AWS' do
8
+
9
+ aws_sns_topic 'mytesttopic1'
10
+ aws_sns_topic 'mytesttopic2'
11
+
12
+ it "creates an aws_cloudwatch_alarm with minimum properties" do
13
+ expect_recipe {
14
+ aws_cloudwatch_alarm 'my-test-alert' do
15
+ namespace 'AWS/EC2'
16
+ metric_name 'CPUUtilization'
17
+ comparison_operator 'GreaterThanThreshold'
18
+ evaluation_periods 1
19
+ period 60
20
+ statistic 'Average'
21
+ threshold 80
22
+ end
23
+ }.to create_an_aws_cloudwatch_alarm('my-test-alert',
24
+ namespace: 'AWS/EC2',
25
+ metric_name: 'CPUUtilization',
26
+ comparison_operator: 'GreaterThanThreshold',
27
+ evaluation_periods: 1,
28
+ period: 60,
29
+ statistic: 'Average',
30
+ threshold: 80,
31
+ actions_enabled: true # this is true by default
32
+ ).and be_idempotent
33
+ end
34
+
35
+ it "creates an aws_cloudwatch_alarm with maximum properties" do
36
+ expect_recipe {
37
+ aws_cloudwatch_alarm 'my-test-alert' do
38
+ namespace 'AWS/EC2'
39
+ metric_name 'CPUUtilization'
40
+ comparison_operator 'GreaterThanThreshold'
41
+ evaluation_periods 1
42
+ period 60
43
+ statistic 'Average'
44
+ threshold 80
45
+ dimensions([
46
+ {
47
+ name: "foo1",
48
+ value: "bar1"
49
+ },
50
+ {
51
+ name: "foo2",
52
+ value: "bar2"
53
+ }
54
+ ])
55
+ insufficient_data_actions ['mytesttopic1']
56
+ ok_actions ['mytesttopic1']
57
+ alarm_actions ['mytesttopic1']
58
+ actions_enabled false
59
+ alarm_description "description"
60
+ unit "Percent"
61
+ end
62
+ }.to create_an_aws_cloudwatch_alarm('my-test-alert',
63
+ namespace: 'AWS/EC2',
64
+ metric_name: 'CPUUtilization',
65
+ comparison_operator: 'GreaterThanThreshold',
66
+ evaluation_periods: 1,
67
+ period: 60,
68
+ statistic: 'Average',
69
+ threshold: 80,
70
+ dimensions: [
71
+ {
72
+ name: "foo1",
73
+ value: "bar1"
74
+ },
75
+ {
76
+ name: "foo2",
77
+ value: "bar2"
78
+ }
79
+ ],
80
+ insufficient_data_actions: [mytesttopic1.aws_object.arn],
81
+ ok_actions: [mytesttopic1.aws_object.arn],
82
+ alarm_actions: [mytesttopic1.aws_object.arn],
83
+ actions_enabled: false,
84
+ alarm_description: "description",
85
+ unit: "Percent",
86
+ ).and be_idempotent
87
+ end
88
+
89
+ context "with an existing minimum cloudwatch alarm" do
90
+ aws_cloudwatch_alarm 'my-test-alert' do
91
+ namespace 'AWS/EC2'
92
+ metric_name 'CPUUtilization'
93
+ comparison_operator 'GreaterThanThreshold'
94
+ evaluation_periods 1
95
+ period 60
96
+ statistic 'Average'
97
+ threshold 80
98
+ end
99
+
100
+ it "updates an aws_cloudwatch_alarm with maximum properties" do
101
+ expect_recipe {
102
+ aws_cloudwatch_alarm 'my-test-alert' do
103
+ namespace 'AWS/EC2'
104
+ metric_name 'CPUUtilization'
105
+ comparison_operator 'GreaterThanThreshold'
106
+ evaluation_periods 1
107
+ period 60
108
+ statistic 'Average'
109
+ threshold 80
110
+ dimensions([
111
+ {
112
+ name: "foo1",
113
+ value: "bar1"
114
+ },
115
+ {
116
+ name: "foo2",
117
+ value: "bar2"
118
+ }
119
+ ])
120
+ insufficient_data_actions ['mytesttopic1']
121
+ ok_actions ['mytesttopic1']
122
+ alarm_actions ['mytesttopic1']
123
+ actions_enabled false
124
+ alarm_description "description"
125
+ unit "Percent"
126
+ end
127
+ }.to update_an_aws_cloudwatch_alarm('my-test-alert',
128
+ namespace: 'AWS/EC2',
129
+ metric_name: 'CPUUtilization',
130
+ comparison_operator: 'GreaterThanThreshold',
131
+ evaluation_periods: 1,
132
+ period: 60,
133
+ statistic: 'Average',
134
+ threshold: 80,
135
+ dimensions: [
136
+ {
137
+ name: "foo1",
138
+ value: "bar1"
139
+ },
140
+ {
141
+ name: "foo2",
142
+ value: "bar2"
143
+ }
144
+ ],
145
+ insufficient_data_actions: [mytesttopic1.aws_object.arn],
146
+ ok_actions: [mytesttopic1.aws_object.arn],
147
+ alarm_actions: [mytesttopic1.aws_object.arn],
148
+ actions_enabled: false,
149
+ alarm_description: "description",
150
+ unit: "Percent",
151
+ ).and be_idempotent
152
+ end
153
+
154
+ end
155
+
156
+ context "with an existing maximum cloudwatch alarm" do
157
+ aws_cloudwatch_alarm 'my-test-alert' do
158
+ namespace 'AWS/EC2'
159
+ metric_name 'CPUUtilization'
160
+ comparison_operator 'GreaterThanThreshold'
161
+ evaluation_periods 1
162
+ period 60
163
+ statistic 'Average'
164
+ threshold 80
165
+ dimensions([
166
+ {
167
+ name: "foo1",
168
+ value: "bar1"
169
+ },
170
+ {
171
+ name: "foo2",
172
+ value: "bar2"
173
+ }
174
+ ])
175
+ insufficient_data_actions ['mytesttopic1']
176
+ ok_actions ['mytesttopic1']
177
+ alarm_actions ['mytesttopic1']
178
+ actions_enabled false
179
+ alarm_description "description"
180
+ unit "Percent"
181
+ end
182
+
183
+ it "updates all updateable attributes" do
184
+ expect_recipe {
185
+ aws_cloudwatch_alarm 'my-test-alert' do
186
+ namespace 'AWS/S3'
187
+ metric_name 'foo'
188
+ comparison_operator 'LessThanThreshold'
189
+ evaluation_periods 2
190
+ period 120
191
+ statistic 'Maximum'
192
+ threshold 70
193
+ dimensions([
194
+ {
195
+ name: "foo3",
196
+ value: "bar3"
197
+ }
198
+ ])
199
+ insufficient_data_actions ['mytesttopic2']
200
+ ok_actions ['mytesttopic1', 'mytesttopic2']
201
+ alarm_actions ['mytesttopic2']
202
+ actions_enabled true
203
+ alarm_description "description2"
204
+ unit "Bits"
205
+ end
206
+ }.to update_an_aws_cloudwatch_alarm('my-test-alert',
207
+ namespace: 'AWS/S3',
208
+ metric_name: 'foo',
209
+ comparison_operator: 'LessThanThreshold',
210
+ evaluation_periods: 2,
211
+ period: 120,
212
+ statistic: 'Maximum',
213
+ threshold: 70,
214
+ dimensions: [
215
+ {
216
+ name: "foo3",
217
+ value: "bar3"
218
+ }
219
+ ],
220
+ insufficient_data_actions: [mytesttopic2.aws_object.arn],
221
+ ok_actions: Set[mytesttopic1.aws_object.arn, mytesttopic2.aws_object.arn],
222
+ alarm_actions: [mytesttopic2.aws_object.arn],
223
+ actions_enabled: true,
224
+ alarm_description: "description2",
225
+ unit: "Bits",
226
+ ).and be_idempotent
227
+ end
228
+
229
+ it "updates only the specified properties" do
230
+ expect_recipe {
231
+ aws_cloudwatch_alarm 'my-test-alert' do
232
+ unit "Gigabytes"
233
+ end
234
+ }.to update_an_aws_cloudwatch_alarm('my-test-alert',
235
+ namespace: 'AWS/S3',
236
+ metric_name: 'foo',
237
+ comparison_operator: 'LessThanThreshold',
238
+ evaluation_periods: 2,
239
+ period: 120,
240
+ statistic: 'Maximum',
241
+ threshold: 70,
242
+ dimensions: [
243
+ {
244
+ name: "foo3",
245
+ value: "bar3"
246
+ }
247
+ ],
248
+ insufficient_data_actions: [mytesttopic2.aws_object.arn],
249
+ ok_actions: Set[mytesttopic1.aws_object.arn, mytesttopic2.aws_object.arn],
250
+ alarm_actions: [mytesttopic2.aws_object.arn],
251
+ actions_enabled: true,
252
+ alarm_description: "description2",
253
+ unit: "Gigabytes",
254
+ ).and be_idempotent
255
+ end
256
+
257
+ it "clears out all clearable arrays" do
258
+ expect_recipe {
259
+ aws_cloudwatch_alarm 'my-test-alert' do
260
+ dimensions []
261
+ insufficient_data_actions []
262
+ ok_actions []
263
+ alarm_actions []
264
+ end
265
+ }.to create_an_aws_cloudwatch_alarm('my-test-alert',
266
+ namespace: 'AWS/S3',
267
+ metric_name: 'foo',
268
+ comparison_operator: 'LessThanThreshold',
269
+ evaluation_periods: 2,
270
+ period: 120,
271
+ statistic: 'Maximum',
272
+ threshold: 70,
273
+ dimensions: [],
274
+ insufficient_data_actions: [],
275
+ ok_actions: [],
276
+ alarm_actions: [],
277
+ actions_enabled: true,
278
+ alarm_description: "description2",
279
+ unit: "Gigabytes",
280
+ ).and be_idempotent
281
+ end
282
+ end
283
+
284
+ end
285
+ end
286
+ end