chef-provisioning-aws 1.5.1 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6fa67263316335a4b0a9df876a8156ee8623bd18
4
- data.tar.gz: 5c09a23f932d5f566d64ba9db95254551549742a
3
+ metadata.gz: 0c186bb7a22b11f6bc9e02f6cc1a2545b6a9889b
4
+ data.tar.gz: 8d58524a6a73a86543eb3f6a62d769bf7afe5fe5
5
5
  SHA512:
6
- metadata.gz: fdbebb79eaad90ed4eb4d850e45351936336f3ad885ec50e83a79fb966f7737b9bea623c40e42eaf461dfce690084cd221077f19abe3faeeade8ac228df984f6
7
- data.tar.gz: 10d6a33fc7a463ffd31b0f0efb70cd32433a6814e32fe7a7187757fac2bf530fcd612e7c90866f4a77e8c7f8840a3bc717e0e40bdbd1a45e7e780d05ced668c1
6
+ metadata.gz: 14c2b8d978b7291fcf5cf52b81f36237df7f0d6dd6f4f2400a999d4f8298301322331444a655fd8b8cfaa5002d52abff00c5c13a608ccf6e8fa717b27e7ee7ae
7
+ data.tar.gz: 44f55a7e710faf8e72f1874ee3b8109fe8522d63f734a5f4f6b1598ff98089a2b8c1f8aac693aeb312320c7cd5d4fc7933eb4d011a934289d656afc943ab166b
data/Gemfile CHANGED
@@ -3,6 +3,4 @@ gem "simplecov"
3
3
  gemspec
4
4
 
5
5
  #gem 'chef-provisioning', path: '../chef-provisioning'
6
- #gem 'chef-provisioning', github: 'chef/chef-provisioning', branch: 'master'
7
- #gem "pry-byebug"
8
- #gem "pry-stack_explorer"
6
+ gem 'chef-provisioning', github: 'chef/chef-provisioning', branch: 'master'
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  This README is a work in progress. Please add to it!
4
4
 
5
- # Prerequesites
5
+ # Prerequisites
6
6
 
7
7
  ## Credentials
8
8
 
@@ -127,10 +127,12 @@ are left that AWS can charge for.
127
127
 
128
128
  # Machine Options
129
129
 
130
- TODO - Finish documenting these
131
-
132
130
  You can pass machine options that will be used by `machine`, `machine_batch` and `machine_image` to
133
- configure the machine. These are all the available options:
131
+ configure the machine.
132
+
133
+ These options are an extension of the [base options](https://github.com/chef/chef-provisioning#machine-options). Please see that for a list of the `machine_options` shared between drivers.
134
+
135
+ The full syntax available in the `bootstrap_options` hash is the hash expected by the AWS [`create_instances`](http://docs.aws.amazon.com/sdkforruby/api/Aws/EC2/Resource.html#create_instances-instance_method) method. The options seen below in the example are the default options.
134
136
 
135
137
  ```ruby
136
138
  with_machine_options({
@@ -146,10 +148,11 @@ with_machine_options({
146
148
  },
147
149
  use_private_ip_for_ssh: false, # DEPRECATED, use `transport_address_location`
148
150
  transport_address_location: :public_ip, # `:public_ip` (default), `:private_ip` or `:dns`. Defines how SSH or WinRM should find an address to communicate with the instance.
151
+ is_windows: true, # false by default
149
152
  })
150
153
  ```
151
154
 
152
- This options hash can be supplied to either `with_machine_options` or directly into the `machine_options`
155
+ This options hash can be supplied to either `with_machine_options` at the recipe level or directly into the `machine_options`
153
156
  attribute.
154
157
 
155
158
  # Load Balancer Options
data/Rakefile CHANGED
@@ -39,7 +39,13 @@ end
39
39
 
40
40
  desc "travis specific task - runs CI integration tests (regular and super_slow in parallel) and sets up travis specific ENV variables"
41
41
  task :travis, [:sub_task] do |t, args|
42
- pattern = "load_balancer_spec.rb,machine_image_spec.rb,aws_iam_instance_profile_spec.rb" # This is a comma seperated list
42
+ pattern = "load_balancer_spec.rb,machine_spec.rb,aws_iam_instance_profile_spec.rb,aws_security_group_spec.rb" # This is a comma seperated list
43
43
  pattern = pattern.split(",").map {|p| "spec/integration/**/*#{p}"}.join(",")
44
44
  Rake::Task[args[:sub_task]].invoke(pattern)
45
45
  end
46
+
47
+ desc "travis task for machine_image tests - these take so long to run that we only run the first test"
48
+ RSpec::Core::RakeTask.new(:machine_image) do |spec|
49
+ spec.pattern = 'spec/integration/machine_image_spec.rb'
50
+ spec.rspec_opts = "-b -t super_slow -e 'machine_image can create an image in the VPC'"
51
+ end
@@ -0,0 +1,37 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/lib')
2
+ require 'chef/provisioning/aws_driver/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'chef-provisioning-aws'
6
+ s.version = Chef::Provisioning::AWSDriver::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.extra_rdoc_files = ['README.md', 'LICENSE' ]
9
+ s.summary = 'Provisioner for creating aws containers in Chef Provisioning.'
10
+ s.description = s.summary
11
+ s.author = 'John Ewart'
12
+ s.email = 'jewart@getchef.com'
13
+ s.homepage = 'https://github.com/opscode/chef-provisioning-aws'
14
+
15
+ s.add_dependency 'chef-provisioning', '~> 1.4'
16
+
17
+ s.add_dependency 'aws-sdk-v1', '>= 1.59.0'
18
+ s.add_dependency 'aws-sdk', '~> 2.1'
19
+ s.add_dependency 'retryable', '~> 2.0.1'
20
+ s.add_dependency 'ubuntu_ami', '~> 0.4.1'
21
+
22
+ # chef-zero is only a development dependency because we leverage its RSpec support
23
+ s.add_development_dependency 'chef-zero', '~> 4.2'
24
+ s.add_development_dependency 'chef', '~> 12.4'
25
+ s.add_development_dependency 'rspec', '~> 3.0'
26
+ s.add_development_dependency 'rake'
27
+ s.add_development_dependency 'pry'
28
+ s.add_development_dependency 'pry-byebug'
29
+ s.add_development_dependency 'pry-stack_explorer'
30
+
31
+ s.bindir = "bin"
32
+ s.executables = %w( )
33
+
34
+ s.require_path = 'lib'
35
+ s.files = %w(Gemfile Rakefile LICENSE README.md) + Dir.glob("*.gemspec") +
36
+ Dir.glob("{distro,lib,tasks,spec}/**/*", File::FNM_DOTMATCH).reject {|f| File.directory?(f) }
37
+ end
@@ -10,6 +10,11 @@ class Chef::Provider::AwsCloudsearchDomain < Chef::Provisioning::AWSDriver::AWSP
10
10
  end
11
11
 
12
12
  update_aws_object(domain)
13
+
14
+ # TODO: since we don't support updating index fields yet,
15
+ # it will not be handled by update_aws_object, so we need to
16
+ # create the index fields here.
17
+ create_index_fields
13
18
  end
14
19
 
15
20
  def destroy_aws_object(domain)
@@ -121,6 +126,12 @@ class Chef::Provider::AwsCloudsearchDomain < Chef::Provisioning::AWSDriver::AWSP
121
126
  cs_client.define_index_field(domain_name: new_resource.name, index_field: field)
122
127
  end
123
128
 
129
+ def create_index_fields
130
+ new_resource.index_fields.each do |field|
131
+ create_index_field(field)
132
+ end
133
+ end
134
+
124
135
  #
125
136
  # API Query Functions
126
137
  #
@@ -52,10 +52,14 @@ class Chef::Provider::AwsInternetGateway < Chef::Provisioning::AWSDriver::AWSPro
52
52
 
53
53
  def attach_vpc(vpc, desired_gateway)
54
54
  if vpc.internet_gateway && vpc.internet_gateway != desired_gateway
55
+ current_driver = self.new_resource.driver
56
+ current_chef_server = self.new_resource.chef_server
55
57
  Cheffish.inline_resource(self, action) do
56
58
  aws_vpc vpc.id do
57
59
  cidr_block vpc.cidr_block
58
60
  internet_gateway false
61
+ driver current_driver
62
+ chef_server current_chef_server
59
63
  end
60
64
  end
61
65
  end
@@ -93,14 +93,14 @@ class Chef::Provider::AwsSecurityGroup < Chef::Provisioning::AWSDriver::AWSProvi
93
93
 
94
94
  authorize: proc do |port_range, protocol, actors|
95
95
  names = actors.map { |a| a.is_a?(Hash) ? a[:group_id] : a }
96
- converge_by "authorize #{names.join(', ')} to send traffic to group #{new_resource.name} (#{sg.id}) on port_range #{port_range} with protocol #{protocol}" do
96
+ converge_by "authorize #{names.join(', ')} to send traffic to group #{new_resource.name} (#{sg.id}) on port_range #{port_range.inspect} with protocol #{protocol || 'nil'}" do
97
97
  sg.authorize_ingress(protocol, port_range, *actors)
98
98
  end
99
99
  end,
100
100
 
101
101
  revoke: proc do |port_range, protocol, actors|
102
102
  names = actors.map { |a| a.is_a?(Hash) ? a[:group_id] : a }
103
- converge_by "revoke the ability of #{names.join(', ')} to send traffic to group #{new_resource.name} (#{sg.id}) on port_range #{port_range} with protocol #{protocol}" do
103
+ converge_by "revoke the ability of #{names.join(', ')} to send traffic to group #{new_resource.name} (#{sg.id}) on port_range #{port_range.inspect} with protocol #{protocol || 'nil'}" do
104
104
  sg.revoke_ingress(protocol, port_range, *actors)
105
105
  end
106
106
  end
@@ -122,8 +122,7 @@ class Chef::Provider::AwsSecurityGroup < Chef::Provisioning::AWSDriver::AWSProvi
122
122
  when Array
123
123
  # [ { port: X, protocol: Y, sources: [ ... ]}]
124
124
  new_resource.outbound_rules.each do |rule|
125
- port_ranges = get_port_ranges(rule)
126
- add_rule(desired_rules, port_ranges, get_actors(vpc, rule[:destinations]))
125
+ add_rule(desired_rules, get_port_ranges(rule), get_actors(vpc, rule[:destinations]))
127
126
  end
128
127
 
129
128
  else
@@ -137,14 +136,14 @@ class Chef::Provider::AwsSecurityGroup < Chef::Provisioning::AWSDriver::AWSProvi
137
136
 
138
137
  authorize: proc do |port_range, protocol, actors|
139
138
  names = actors.map { |a| a.is_a?(Hash) ? a[:group_id] : a }
140
- converge_by "authorize group #{new_resource.name} (#{sg.id}) to send traffic to #{names.join(', ')} on port_range #{port_range} with protocol #{protocol}" do
139
+ converge_by "authorize group #{new_resource.name} (#{sg.id}) to send traffic to #{names.join(', ')} on port_range #{port_range.inspect} with protocol #{protocol || 'nil'}" do
141
140
  sg.authorize_egress(*actors, ports: port_range, protocol: protocol)
142
141
  end
143
142
  end,
144
143
 
145
144
  revoke: proc do |port_range, protocol, actors|
146
145
  names = actors.map { |a| a.is_a?(Hash) ? a[:group_id] : a }
147
- converge_by "revoke the ability of group #{new_resource.name} (#{sg.id}) to send traffic to #{names.join(', ')} on port_range #{port_range} with protocol #{protocol}" do
146
+ converge_by "revoke the ability of group #{new_resource.name} (#{sg.id}) to send traffic to #{names.join(', ')} on port_range #{port_range.inspect} with protocol #{protocol || 'nil'}" do
148
147
  sg.revoke_egress(*actors, ports: port_range, protocol: protocol)
149
148
  end
150
149
  end
@@ -203,29 +202,43 @@ class Chef::Provider::AwsSecurityGroup < Chef::Provisioning::AWSDriver::AWSProvi
203
202
  end
204
203
  end
205
204
 
205
+ # When protocol is unspecified (anything besides tcp, udp or icmp) then
206
+ # you cannot specify ports. When specifying tcp, udp, or icmp AWS wants
207
+ # port_range 0..0. -1..-1 will cause error
206
208
  def get_port_ranges(port_spec)
207
209
  case port_spec
208
210
  when Integer
211
+ port_spec = 0 if port_spec == -1
209
212
  [ { port_range: port_spec..port_spec, protocol: :tcp } ]
210
213
  when Range
214
+ port_spec = 0..0 if port_spec == (-1..-1)
211
215
  [ { port_range: port_spec, protocol: :tcp } ]
212
216
  when Array
213
217
  port_spec.map { |p| get_port_ranges(p) }.flatten
214
- when :icmp
215
- { port_range: port_spec, protocol: :icmp }
218
+ when String, Symbol
219
+ protocol = port_spec.to_s.downcase.to_sym
220
+ if protocol.to_s =~ /(any|all|-1)/i
221
+ [ { port_range: -1..-1, protocol: :"-1" } ]
222
+ else
223
+ [ { port_range: 0..0, protocol: protocol } ]
224
+ end
216
225
  when Hash
217
- port_range = port_spec[:port_range] || port_spec[:ports] || port_spec[:port]
226
+ port_range = port_spec[:port_range] || port_spec[:ports] || port_spec[:port] || 0
218
227
  port_range = port_range..port_range if port_range.is_a?(Integer)
219
228
  if port_spec[:protocol]
220
- port_range ||= -1..-1
221
- [ { port_range: port_range, protocol: port_spec[:protocol].to_s.to_sym || :tcp } ]
229
+ protocol = port_spec[:protocol].to_s.downcase.to_sym
230
+ if protocol.to_s =~ /(any|all|-1)/i
231
+ [ { port_range: -1..-1, protocol: :"-1" } ]
232
+ else
233
+ [ { port_range: port_range, protocol: protocol } ]
234
+ end
222
235
  else
223
236
  get_port_ranges(port_range)
224
237
  end
225
238
  # The to_s.to_sym dance is because if you specify a protocol number, AWS symbolifies it,
226
239
  # but 26.to_sym doesn't work (so we have to to_s it first).
227
240
  when nil
228
- [ { port_range: nil, protocol: :any } ]
241
+ [ { port_range: -1..-1, protocol: :"-1" } ]
229
242
  end
230
243
  end
231
244
 
@@ -251,7 +264,7 @@ class Chef::Provider::AwsSecurityGroup < Chef::Provisioning::AWSDriver::AWSProvi
251
264
 
252
265
  # load_balancer: <load balancer name>
253
266
  elsif actor_spec.keys == [ :load_balancer ]
254
- lb = Chef::Resource::AwsLoadBalancer.get_aws_object(actor_spec.values.first, resource: new_resource)
267
+ lb = Chef::Resource::AwsLoadBalancer.get_aws_object(actor_spec[:load_balancer], resource: new_resource)
255
268
  get_actors(vpc, lb)
256
269
 
257
270
  # security_group: <security group name>
@@ -278,7 +291,7 @@ class Chef::Provider::AwsSecurityGroup < Chef::Provisioning::AWSDriver::AWSProvi
278
291
  IPAddr.new(actor_spec)
279
292
  # Add /32 to the end of raw IP addresses
280
293
  actor_spec =~ /\// ? actor_spec : "#{actor_spec}/32"
281
- rescue
294
+ rescue IPAddr::InvalidAddressError
282
295
  Chef::Resource::AwsSecurityGroup.get_aws_object(actor_spec, resource: new_resource)
283
296
  end
284
297
 
@@ -61,17 +61,28 @@ class Chef::Provider::AwsSubnet < Chef::Provisioning::AWSDriver::AWSProvider
61
61
  if purging
62
62
  # TODO possibly convert to http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/EC2/Client.html#terminate_instances-instance_method
63
63
  p = Chef::ChefFS::Parallelizer.new(5)
64
+ current_driver = self.new_resource.driver
65
+ current_chef_server = self.new_resource.chef_server
64
66
  p.parallel_do(subnet.instances.to_a) do |instance|
65
67
  Cheffish.inline_resource(self, action) do
66
68
  aws_instance instance.id do
67
69
  action :purge
70
+ driver current_driver
71
+ chef_server current_chef_server
68
72
  end
69
73
  end
70
74
  end
71
75
  p.parallel_do(subnet.network_interfaces.to_a) do |network|
72
- Cheffish.inline_resource(self, action) do
73
- aws_network_interface network do
74
- action :purge
76
+ # It is common during subnet purging for the instance to be terminated but
77
+ # temporarily hanging around - this causes a `The network interface at device index 0 cannot be detached`
78
+ # error to be raised when trying to detach
79
+ retry_with_backoff(AWS::EC2::Errors::OperationNotPermitted) do
80
+ Cheffish.inline_resource(self, action) do
81
+ aws_network_interface network do
82
+ action :purge
83
+ driver current_driver
84
+ chef_server current_chef_server
85
+ end
75
86
  end
76
87
  end
77
88
  end
@@ -65,31 +65,46 @@ class Chef::Provider::AwsVpc < Chef::Provisioning::AWSDriver::AWSProvider
65
65
  end
66
66
 
67
67
  def destroy_aws_object(vpc)
68
+ current_driver = self.new_resource.driver
69
+ current_chef_server = self.new_resource.chef_server
68
70
  if purging
69
71
  vpc.subnets.each do |s|
70
72
  Cheffish.inline_resource(self, action) do
71
73
  aws_subnet s do
72
74
  action :purge
75
+ driver current_driver
76
+ chef_server current_chef_server
73
77
  end
74
78
  end
75
79
  end
76
80
  # If any of the below resources start needing complicated delete logic (dependent resources needing to
77
81
  # be deleted) move that logic into `delete_aws_resource` and add the purging logic to the resource
78
- vpc.network_acls.each { |o| o.delete unless o.default? }
82
+ vpc.network_acls.each do |na|
83
+ next if na.default?
84
+ Cheffish.inline_resource(self, action) do
85
+ aws_network_acl na do
86
+ action :purge
87
+ driver current_driver
88
+ chef_server current_chef_server
89
+ end
90
+ end
91
+ end
79
92
  vpc.network_interfaces.each do |ni|
80
93
  Cheffish.inline_resource(self, action) do
81
94
  aws_network_interface ni do
82
95
  action :purge
96
+ driver current_driver
97
+ chef_server current_chef_server
83
98
  end
84
99
  end
85
100
  end
86
-
87
101
  vpc.security_groups.each do |sg|
88
- unless sg.name == 'default'
89
- Cheffish.inline_resource(self, action) do
90
- aws_security_group sg do
91
- action :purge
92
- end
102
+ next if sg.name == 'default'
103
+ Cheffish.inline_resource(self, action) do
104
+ aws_security_group sg do
105
+ action :purge
106
+ driver current_driver
107
+ chef_server current_chef_server
93
108
  end
94
109
  end
95
110
  end
@@ -97,11 +112,12 @@ class Chef::Provider::AwsVpc < Chef::Provisioning::AWSDriver::AWSProvider
97
112
  #SDK V2
98
113
  vpc_new_sdk = new_resource.driver.ec2_resource.vpc(vpc.id)
99
114
  vpc_new_sdk.route_tables.each do |rt|
100
- unless rt.associations.any? { |association| association.main }
101
- Cheffish.inline_resource(self, action) do
102
- aws_route_table rt do
103
- action :purge
104
- end
115
+ next if rt.associations.any? { |association| association.main }
116
+ Cheffish.inline_resource(self, action) do
117
+ aws_route_table rt do
118
+ action :purge
119
+ driver current_driver
120
+ chef_server current_chef_server
105
121
  end
106
122
  end
107
123
  end
@@ -126,6 +142,8 @@ class Chef::Provider::AwsVpc < Chef::Provisioning::AWSDriver::AWSProvider
126
142
  Cheffish.inline_resource(self, action) do
127
143
  aws_vpc_peering_connection pc_resource do
128
144
  action :purge
145
+ driver current_driver
146
+ chef_server current_chef_server
129
147
  end
130
148
  end
131
149
  end
@@ -141,6 +159,8 @@ class Chef::Provider::AwsVpc < Chef::Provisioning::AWSDriver::AWSProvider
141
159
  else
142
160
  action :detach
143
161
  end
162
+ driver current_driver
163
+ chef_server current_chef_server
144
164
  end
145
165
  end
146
166
  end
@@ -179,6 +199,8 @@ class Chef::Provider::AwsVpc < Chef::Provisioning::AWSDriver::AWSProvider
179
199
 
180
200
  def update_internet_gateway(vpc)
181
201
  current_ig = vpc.internet_gateway
202
+ current_driver = self.new_resource.driver
203
+ current_chef_server = self.new_resource.chef_server
182
204
  case new_resource.internet_gateway
183
205
  when String, Chef::Resource::AwsInternetGateway, AWS::EC2::InternetGateway
184
206
  new_ig = Chef::Resource::AwsInternetGateway.get_aws_object(new_resource.internet_gateway, resource: new_resource)
@@ -186,6 +208,12 @@ class Chef::Provider::AwsVpc < Chef::Provisioning::AWSDriver::AWSProvider
186
208
  Cheffish.inline_resource(self, action) do
187
209
  aws_internet_gateway new_ig do
188
210
  vpc vpc.id
211
+ # We have to set the driver & chef server on all resources because
212
+ # `with_chef_driver(...) do` gets evaluated at compile-time and these
213
+ # resources aren't constructed until converge-time. So the driver has
214
+ # been reset at this point
215
+ driver current_driver
216
+ chef_server current_chef_server
189
217
  end
190
218
  end
191
219
  elsif current_ig != new_ig
@@ -196,9 +224,13 @@ class Chef::Provider::AwsVpc < Chef::Provisioning::AWSDriver::AWSProvider
196
224
  else
197
225
  action :detach
198
226
  end
227
+ driver current_driver
228
+ chef_server current_chef_server
199
229
  end
200
230
  aws_internet_gateway new_ig do
201
231
  vpc vpc.id
232
+ driver current_driver
233
+ chef_server current_chef_server
202
234
  end
203
235
  end
204
236
  end
@@ -208,6 +240,8 @@ class Chef::Provider::AwsVpc < Chef::Provisioning::AWSDriver::AWSProvider
208
240
  aws_internet_gateway "igw-managed-by-#{vpc.id}" do
209
241
  vpc vpc.id
210
242
  aws_tags 'OwnedByVPC' => vpc.id
243
+ driver current_driver
244
+ chef_server current_chef_server
211
245
  end
212
246
  end
213
247
  end
@@ -220,6 +254,8 @@ class Chef::Provider::AwsVpc < Chef::Provisioning::AWSDriver::AWSProvider
220
254
  else
221
255
  action :detach
222
256
  end
257
+ driver current_driver
258
+ chef_server current_chef_server
223
259
  end
224
260
  end
225
261
  end
@@ -250,10 +286,14 @@ class Chef::Provider::AwsVpc < Chef::Provisioning::AWSDriver::AWSProvider
250
286
  # creating the VPC
251
287
  main_route_table ||= vpc.route_tables.main_route_table
252
288
  main_routes = new_resource.main_routes
289
+ current_driver = self.new_resource.driver
290
+ current_chef_server = self.new_resource.chef_server
253
291
  Cheffish.inline_resource(self, action) do
254
292
  aws_route_table main_route_table.id do
255
293
  vpc vpc
256
294
  routes main_routes
295
+ driver current_driver
296
+ chef_server current_chef_server
257
297
  end
258
298
  end
259
299
  main_route_table
@@ -575,15 +575,28 @@ EOD
575
575
  end
576
576
 
577
577
  if instance.state.name != "running"
578
- wait_until_machine(action_handler, machine_spec, "finish stopping", instance) { instance.state.name != "stopping" }
578
+ wait_until_machine(action_handler, machine_spec, "finish stopping", instance) { |instance| instance.state.name != "stopping" }
579
579
  if instance.state.name == "stopped"
580
580
  action_handler.perform_action "Start #{machine_spec.name} (#{machine_spec.reference['instance_id']}) in #{aws_config.region} ..." do
581
581
  instance.start
582
582
  end
583
583
  end
584
- wait_until_ready_machine(action_handler, machine_spec, instance)
584
+ wait_until_instance_running(action_handler, machine_spec, instance)
585
585
  end
586
586
 
587
+ # Windows machines potentially do a bunch of extra stuff - setting hostname,
588
+ # sending out encrypted password, restarting instance, etc.
589
+ if machine_spec.reference['is_windows']
590
+ wait_until_machine(action_handler, machine_spec, "receive 'Windows is ready' message from the AWS console", instance) { |instance|
591
+ output = instance.console_output.output
592
+ if output.nil? || output.empty?
593
+ false
594
+ else
595
+ output = Base64.decode64(output)
596
+ output =~ /Message: Windows is Ready to use/
597
+ end
598
+ }
599
+ end
587
600
  wait_for_transport(action_handler, machine_spec, machine_options)
588
601
  machine_for(machine_spec, machine_options, instance)
589
602
  end
@@ -598,6 +611,19 @@ EOD
598
611
  machine_for(machine_spec, machine_spec.reference)
599
612
  end
600
613
 
614
+ def stop_machine(action_handler, machine_spec, machine_options)
615
+ instance = instance_for(machine_spec)
616
+ if instance && instance.exists?
617
+ wait_until_machine(action_handler, machine_spec, "finish coming up so we can stop it", instance) { |instance| instance.state.name != "pending" }
618
+ if instance.state.name == "running"
619
+ action_handler.perform_action "Stop #{machine_spec.name} (#{instance.id}) in #{aws_config.region} ..." do
620
+ instance.stop
621
+ end
622
+ end
623
+ wait_until_machine(action_handler, machine_spec, "stop", instance) { |instance| %w[stopped terminated].include?(instance.state.name) }
624
+ end
625
+ end
626
+
601
627
  def destroy_machine(action_handler, machine_spec, machine_options)
602
628
  d = self
603
629
  Provisioning.inline_resource(action_handler) do
@@ -894,15 +920,22 @@ EOD
894
920
  endpoint = "http://#{remote_host}:#{port}/wsman"
895
921
  type = :plaintext
896
922
  pem_bytes = get_private_key(instance.key_name)
897
- encrypted_admin_password = wait_for_admin_password(machine_spec)
898
923
 
899
- decoded = Base64.decode64(encrypted_admin_password)
900
- private_key = OpenSSL::PKey::RSA.new(pem_bytes)
901
- decrypted_password = private_key.private_decrypt decoded
924
+ # TODO plaintext password = bad
925
+ password = machine_spec.reference['winrm_password']
926
+ if password.nil? || password.empty?
927
+ encrypted_admin_password = instance.password_data.password_data
928
+ if encrypted_admin_password.nil? || encrypted_admin_password.empty?
929
+ raise "You did not specify winrm_password in the machine options and no encrytpted password could be fetched from the instance"
930
+ end
931
+ decoded = Base64.decode64(encrypted_admin_password)
932
+ private_key = OpenSSL::PKey::RSA.new(pem_bytes)
933
+ password = private_key.private_decrypt decoded
934
+ end
902
935
 
903
936
  winrm_options = {
904
937
  :user => machine_spec.reference['winrm_username'] || 'Administrator',
905
- :pass => decrypted_password,
938
+ :pass => password,
906
939
  :disable_sspi => true,
907
940
  :basic_auth_only => true
908
941
  }
@@ -910,30 +943,6 @@ EOD
910
943
  Chef::Provisioning::Transport::WinRM.new("#{endpoint}", type, winrm_options, {})
911
944
  end
912
945
 
913
- def wait_for_admin_password(machine_spec)
914
- time_elapsed = 0
915
- sleep_time = 10
916
- max_wait_time = 900 # 15 minutes
917
- encrypted_admin_password = nil
918
- instance_id = machine_spec.reference['instance_id']
919
-
920
- Chef::Log.info "waiting for #{machine_spec.name}'s admin password to be available..."
921
- while time_elapsed < max_wait_time && encrypted_admin_password.nil?
922
- response = ec2.client.get_password_data({ :instance_id => instance_id })
923
- encrypted_admin_password = response['password_data'.to_sym]
924
-
925
- if encrypted_admin_password.nil?
926
- Chef::Log.info "#{time_elapsed}/#{max_wait_time}s elapsed -- sleeping #{sleep_time} for #{machine_spec.name}'s admin password."
927
- sleep(sleep_time)
928
- time_elapsed += sleep_time
929
- end
930
- end
931
-
932
- Chef::Log.info "#{machine_spec.name}'s admin password is available!"
933
-
934
- encrypted_admin_password
935
- end
936
-
937
946
  def create_ssh_transport(machine_spec, machine_options, instance)
938
947
  ssh_options = ssh_options_for(machine_spec, machine_options, instance)
939
948
  username = machine_spec.reference['ssh_username'] || machine_options[:ssh_username] || default_ssh_username
@@ -1053,7 +1062,7 @@ EOD
1053
1062
  end
1054
1063
  end
1055
1064
 
1056
- def wait_until_ready_machine(action_handler, machine_spec, instance=nil)
1065
+ def wait_until_instance_running(action_handler, machine_spec, instance=nil)
1057
1066
  wait_until_machine(action_handler, machine_spec, "be ready", instance) { |instance|
1058
1067
  instance.state.name == "running"
1059
1068
  }
@@ -1252,7 +1261,7 @@ EOD
1252
1261
  end
1253
1262
  machine_options = Cheffish::MergedConfig.new(machine_options, {:transport_address_location => :private_ip})
1254
1263
  end
1255
- %w(is_windows ssh_username sudo transport_address_location ssh_gateway).each do |key|
1264
+ %w(is_windows winrm_username winrm_port winrm_password ssh_username sudo transport_address_location ssh_gateway).each do |key|
1256
1265
  machine_spec.reference[key] = machine_options[key.to_sym] if machine_options[key.to_sym]
1257
1266
  end
1258
1267
  instance
@@ -1,7 +1,7 @@
1
1
  class Chef
2
2
  module Provisioning
3
3
  module AWSDriver
4
- VERSION = '1.5.1'
4
+ VERSION = '1.6.0'
5
5
  end
6
6
  end
7
7
  end
@@ -1,3 +1,3 @@
1
- require 'chef/provisioning/aws_driver/driver'
1
+ require 'chef/provisioning/aws_driver'
2
2
 
3
3
  Chef::Provisioning.register_driver_class('aws', Chef::Provisioning::AWSDriver::Driver)
data/spec/aws_support.rb CHANGED
@@ -171,7 +171,9 @@ module AWSSupport
171
171
  context.module_eval do
172
172
  after :example do
173
173
  # Close up delayed streams so they don't print out their garbage later in the run
174
- delayed_streams.each { |s| s.close }
174
+ unless chef_config[:include_output_after_example]
175
+ delayed_streams.each { |s| s.close }
176
+ end
175
177
 
176
178
  # Destroy any objects we know got created during the test
177
179
  created_during_test.reverse_each do |resource_name, name|
@@ -43,9 +43,20 @@ module AWSSupport
43
43
  if ! actual_setlike.respond_to?(:to_set)
44
44
  result << "expected #{identifier || "setlike"} to be castable to a Set, but it isn't!"
45
45
  else
46
- if ! actual_setlike.to_set == expected_set
47
-
48
- result << "expected #{identifier || "setlike"} to #{description_of(expected_value)}"
46
+ actual_set = actual_setlike.to_set
47
+ expected_set.each do |expected|
48
+ unless actual_set.any? { |actual|
49
+ match_values_failure_messages(expected, actual, identifier).flatten.empty?
50
+ }
51
+ result << "- #{description_of(expected)}"
52
+ end
53
+ end
54
+ actual_set.each do |actual|
55
+ unless expected_set.any? { |expected|
56
+ match_values_failure_messages(expected, actual, identifier).flatten.empty?
57
+ }
58
+ result << "+ #{description_of(actual)}"
59
+ end
49
60
  end
50
61
  end
51
62
  result
@@ -8,7 +8,7 @@ module AWSSupport
8
8
  include RSpec::Matchers::Composable
9
9
  include AWSSupport::DeepMatcher
10
10
 
11
- # @param custom_matcher [Block] A block with 1 argument that will be provided the aws_obect
11
+ # @param custom_matcher [Block] A block with 1 argument that will be provided the aws_object
12
12
  def initialize(example, resource_class, name, expected_values, custom_matcher)
13
13
  @example = example
14
14
  @resource_class = resource_class
@@ -105,8 +105,14 @@ describe Chef::Resource::AwsSecurityGroup do
105
105
  end
106
106
 
107
107
  with_aws "in a VPC" do
108
- aws_vpc 'test_vpc' do
109
- cidr_block '10.0.0.0/24'
108
+ purge_all
109
+ setup_public_vpc
110
+
111
+ load_balancer "testloadbalancer" do
112
+ load_balancer_options({
113
+ subnets: ["test_public_subnet"],
114
+ security_groups: ["test_security_group"]
115
+ })
110
116
  end
111
117
 
112
118
  it "aws_security_group 'test_sg' with no attributes works" do
@@ -121,35 +127,343 @@ describe Chef::Resource::AwsSecurityGroup do
121
127
  ).and be_idempotent
122
128
  end
123
129
 
124
- it "aws_security_group 'test_sg' with inbound and outbound rules works" do
130
+ it "can specify rules as a mapping from source/destination to port and protocol" do
125
131
  expect_recipe {
126
132
  aws_security_group 'test_sg' do
133
+ # We need to define a list of ports and its easier to use a method than
134
+ # have to add a new number when changing this test
135
+ def counter()
136
+ @ip_counter ||= 0
137
+ @ip_counter += 1
138
+ end
139
+
127
140
  vpc 'test_vpc'
128
- inbound_rules '0.0.0.0/0' => 22
129
- outbound_rules 22 => '0.0.0.0/0'
141
+ inbound_rules(
142
+ "10.0.0.#{counter}/32" => { port_range: -1..-1, protocol: -1 },
143
+ "10.0.0.#{counter}/32" => { port: -1, protocol: -1 },
144
+ "10.0.0.#{counter}/32" => { port: 1002, protocol: -1 },
145
+ "10.0.0.#{counter}/32" => { ports: 1003..1003, protocol: -1 },
146
+ "10.0.0.#{counter}/32" => { port_range: 1004..1005, protocol: -1 },
147
+ "10.0.0.#{counter}/32" => { port_range: [1006, 1007, 1108], protocol: -1 },
148
+ # If the protocol isn't `-1` and you don't specify all the ports
149
+ # aws wants `port_range` to be nil
150
+ "10.0.0.#{counter}/32" => { ports: nil, protocol: :tcp },
151
+ "10.0.0.#{counter}/32" => { port_range: 0..65535, protocol: :udp },
152
+ "10.0.0.#{counter}/32" => { port_range: -1, protocol: :icmp },
153
+ "10.0.0.#{counter}/32" => { port_range: 1..2, protocol: :icmp },
154
+ "10.0.0.#{counter}/32" => { port_range: 1011, protocol: :any },
155
+ "10.0.0.#{counter}/32" => { port_range: 1012, protocol: nil },
156
+ "10.0.0.#{counter}/32" => { port: 1013 },
157
+ "10.0.0.#{counter}/32" => { port: 1014..1014 },
158
+ "10.0.0.#{counter}/32" => { port: [1015, 1016, 1117] },
159
+ "10.0.0.#{counter}/32" => { port: :icmp },
160
+ "10.0.0.#{counter}/32" => { port: 'tCp' },
161
+ "10.0.0.#{counter}/32" => { port: nil },
162
+ "10.0.0.#{counter}/32" => { protocol: -1 },
163
+ "10.0.0.#{counter}/32" => { protocol: :any },
164
+ "10.0.0.#{counter}/32" => { protocol: 'UDP' },
165
+ "10.0.0.#{counter}/32" => { protocol: nil },
166
+ "10.0.0.#{counter}/32" => 1020,
167
+ "10.0.0.#{counter}/32" => 1021..1023,
168
+ "10.0.0.#{counter}/32" => [1024, 1025, 1125],
169
+ "10.0.0.#{counter}/32" => :icmp,
170
+ "10.0.0.#{counter}/32" => 'Icmp',
171
+ "10.0.0.#{counter}/32" => :tcp,
172
+ "10.0.0.#{counter}/32" => 'UDP',
173
+ "10.0.0.#{counter}/32" => nil,
174
+ "10.0.0.#{counter}/32" => -1,
175
+ "10.0.0.#{counter}/32" => :"-1",
176
+ ["10.0.0.#{counter}/32", "10.0.0.#{counter}/32"] => :all,
177
+ 'test_security_group' => 1200,
178
+ test_security_group.aws_object.id => 1201,
179
+ test_security_group.aws_object => 1202,
180
+ test_security_group => 1203,
181
+ # cannot get the ID from the v1 api object
182
+ #testloadbalancer.aws_object.id => 1205,
183
+ testloadbalancer.aws_object => 1206,
184
+ # Cannot specify a LoadBalancer resource, only AwsLoadBalancer
185
+ #testloadbalancer => 1207,
186
+ {group_name: 'test_security_group'} => 1208,
187
+ {load_balancer: 'testloadbalancer'} => 1209,
188
+ {security_group: 'test_security_group'} => 1210,
189
+ )
190
+ outbound_rules(
191
+ { port_range: -1..-1, protocol: -1 } => "10.0.0.#{counter}/32",
192
+ { port: -1, protocol: -1 } => "10.0.0.#{counter}/32",
193
+ { port: 1002, protocol: -1 } => "10.0.0.#{counter}/32",
194
+ { ports: 1003..1003, protocol: -1 } => "10.0.0.#{counter}/32",
195
+ { port_range: 1004..1005, protocol: -1 } => "10.0.0.#{counter}/32",
196
+ { port_range: [1006, 1007, 1108], protocol: -1 } => "10.0.0.#{counter}/32",
197
+ # If the protocol isn't `-1` and you don't specify all the ports
198
+ # aws wants `port_range` to be nil{ ports: nil, protocol: :tcp } => "10.0.0.#{counter}/32",
199
+ { port_range: 0..65535, protocol: :udp } => "10.0.0.#{counter}/32",
200
+ { port_range: -1, protocol: :icmp } => "10.0.0.#{counter}/32",
201
+ { port_range: 1..2, protocol: :icmp } => "10.0.0.#{counter}/32",
202
+ { port_range: 1011, protocol: :any } => "10.0.0.#{counter}/32",
203
+ { port_range: 1012, protocol: nil } => "10.0.0.#{counter}/32",
204
+ { port: 1013 } => "10.0.0.#{counter}/32",
205
+ { port: 1014..1014 } => "10.0.0.#{counter}/32",
206
+ { port: [1015, 1016, 1117] } => "10.0.0.#{counter}/32",
207
+ { port: :icmp } => "10.0.0.#{counter}/32",
208
+ { port: 'tCp' } => "10.0.0.#{counter}/32",
209
+ { port: nil } => "10.0.0.#{counter}/32",
210
+ { protocol: -1 } => "10.0.0.#{counter}/32",
211
+ { protocol: :any } => "10.0.0.#{counter}/32",
212
+ { protocol: 'UDP' } => "10.0.0.#{counter}/32",
213
+ { protocol: nil } => "10.0.0.#{counter}/32",
214
+ 1020 => "10.0.0.#{counter}/32",
215
+ 1021..1023 => "10.0.0.#{counter}/32",
216
+ [1024, 1025, 1125] => "10.0.0.#{counter}/32",
217
+ :icmp => "10.0.0.#{counter}/32",
218
+ 'Icmp' => "10.0.0.#{counter}/32",
219
+ :tcp => "10.0.0.#{counter}/32",
220
+ 'UDP' => "10.0.0.#{counter}/32",
221
+ nil => "10.0.0.#{counter}/32",
222
+ -1 => "10.0.0.#{counter}/32",
223
+ :"-1" => "10.0.0.#{counter}/32",
224
+ :all => ["10.0.0.#{counter}/32", "10.0.0.#{counter}/32"],
225
+ 1200 => 'test_security_group',
226
+ 1201 => test_security_group.aws_object.id,
227
+ 1202 => test_security_group.aws_object,
228
+ 1203 => test_security_group,
229
+ # cannot get the ID from the v1 api object
230
+ #1205 => testloadbalancer.aws_object.id,
231
+ 1206 => testloadbalancer.aws_object,
232
+ # Cannot specify a LoadBalancer resource, only AwsLoadBalancer
233
+ #1207 => testloadbalancer,
234
+ 1208 => {group_name: 'test_security_group'},
235
+ 1209 => {load_balancer: 'testloadbalancer'},
236
+ 1210 => {security_group: 'test_security_group'},
237
+ )
130
238
  end
131
239
  }.to create_an_aws_security_group('test_sg',
132
240
  vpc_id: test_vpc.aws_object.id,
133
- ip_permissions_list: [
134
- { groups: [], ip_ranges: [{cidr_ip: "0.0.0.0/0"}], ip_protocol: "tcp", from_port: 22, to_port: 22},
241
+ ip_permissions_list: Set[
242
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.1/32"}, {:cidr_ip=>"10.0.0.11/32"}, {:cidr_ip=>"10.0.0.19/32"}, {:cidr_ip=>"10.0.0.2/32"}, {:cidr_ip=>"10.0.0.20/32"}, {:cidr_ip=>"10.0.0.3/32"}, {:cidr_ip=>"10.0.0.30/32"}, {:cidr_ip=>"10.0.0.32/32"}, {:cidr_ip=>"10.0.0.33/32"}, {:cidr_ip=>"10.0.0.34/32"}, {:cidr_ip=>"10.0.0.4/32"}, {:cidr_ip=>"10.0.0.5/32"}, {:cidr_ip=>"10.0.0.6/32"}], :ip_protocol=>"-1"},
243
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.17/32"}, {:cidr_ip=>"10.0.0.18/32"}, {:cidr_ip=>"10.0.0.22/32"}, {:cidr_ip=>"10.0.0.28/32"}, {:cidr_ip=>"10.0.0.31/32"}, {:cidr_ip=>"10.0.0.7/32"}], :ip_protocol=>"tcp", :from_port=>0, :to_port=>0},
244
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.8/32"}], :ip_protocol=>"udp", :from_port=>0, :to_port=>65535},
245
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.9/32"}], :ip_protocol=>"icmp", :from_port=>-1, :to_port=>-1},
246
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.10/32"}], :ip_protocol=>"icmp", :from_port=>1, :to_port=>2},
247
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.12/32"}], :ip_protocol=>"tcp", :from_port=>1012, :to_port=>1012},
248
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.13/32"}], :ip_protocol=>"tcp", :from_port=>1013, :to_port=>1013},
249
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.14/32"}], :ip_protocol=>"tcp", :from_port=>1014, :to_port=>1014},
250
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.15/32"}], :ip_protocol=>"tcp", :from_port=>1117, :to_port=>1117},
251
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.15/32"}], :ip_protocol=>"tcp", :from_port=>1015, :to_port=>1015},
252
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.15/32"}], :ip_protocol=>"tcp", :from_port=>1016, :to_port=>1016},
253
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.16/32"}, {:cidr_ip=>"10.0.0.26/32"}, {:cidr_ip=>"10.0.0.27/32"}], :ip_protocol=>"icmp", :from_port=>0, :to_port=>0},
254
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.21/32"}, {:cidr_ip=>"10.0.0.29/32"}], :ip_protocol=>"udp", :from_port=>0, :to_port=>0},
255
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.23/32"}], :ip_protocol=>"tcp", :from_port=>1020, :to_port=>1020},
256
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.24/32"}], :ip_protocol=>"tcp", :from_port=>1021, :to_port=>1023},
257
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.25/32"}], :ip_protocol=>"tcp", :from_port=>1024, :to_port=>1024},
258
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.25/32"}], :ip_protocol=>"tcp", :from_port=>1025, :to_port=>1025},
259
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.25/32"}], :ip_protocol=>"tcp", :from_port=>1125, :to_port=>1125},
260
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1200, :to_port=>1200},
261
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1201, :to_port=>1201},
262
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1202, :to_port=>1202},
263
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1203, :to_port=>1203},
264
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1206, :to_port=>1206},
265
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1208, :to_port=>1208},
266
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1209, :to_port=>1209},
267
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1210, :to_port=>1210}
135
268
  ],
136
- ip_permissions_list_egress: [{groups: [], ip_ranges: [{cidr_ip: "0.0.0.0/0"}], ip_protocol: "tcp", from_port: 22, to_port: 22 }]
269
+ ip_permissions_list_egress: Set[
270
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.35/32"}, {:cidr_ip=>"10.0.0.36/32"}, {:cidr_ip=>"10.0.0.37/32"}, {:cidr_ip=>"10.0.0.38/32"}, {:cidr_ip=>"10.0.0.39/32"}, {:cidr_ip=>"10.0.0.40/32"}, {:cidr_ip=>"10.0.0.44/32"}, {:cidr_ip=>"10.0.0.52/32"}, {:cidr_ip=>"10.0.0.53/32"}, {:cidr_ip=>"10.0.0.63/32"}, {:cidr_ip=>"10.0.0.65/32"}, {:cidr_ip=>"10.0.0.66/32"}, {:cidr_ip=>"10.0.0.67/32"}], :ip_protocol=>"-1"},
271
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.41/32"}], :ip_protocol=>"udp", :from_port=>0, :to_port=>65535},
272
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.42/32"}], :ip_protocol=>"icmp", :from_port=>-1, :to_port=>-1},
273
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.43/32"}], :ip_protocol=>"icmp", :from_port=>1, :to_port=>2},
274
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.45/32"}], :ip_protocol=>"tcp", :from_port=>1012, :to_port=>1012},
275
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.46/32"}], :ip_protocol=>"tcp", :from_port=>1013, :to_port=>1013},
276
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.47/32"}], :ip_protocol=>"tcp", :from_port=>1014, :to_port=>1014},
277
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.48/32"}], :ip_protocol=>"tcp", :from_port=>1015, :to_port=>1015},
278
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.48/32"}], :ip_protocol=>"tcp", :from_port=>1016, :to_port=>1016},
279
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.48/32"}], :ip_protocol=>"tcp", :from_port=>1117, :to_port=>1117},
280
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.49/32"}, {:cidr_ip=>"10.0.0.59/32"}, {:cidr_ip=>"10.0.0.60/32"}], :ip_protocol=>"icmp", :from_port=>0, :to_port=>0},
281
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.50/32"}, {:cidr_ip=>"10.0.0.51/32"}, {:cidr_ip=>"10.0.0.55/32"}, {:cidr_ip=>"10.0.0.61/32"}, {:cidr_ip=>"10.0.0.64/32"}], :ip_protocol=>"tcp", :from_port=>0, :to_port=>0},
282
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.54/32"}, {:cidr_ip=>"10.0.0.62/32"}], :ip_protocol=>"udp", :from_port=>0, :to_port=>0},
283
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.56/32"}], :ip_protocol=>"tcp", :from_port=>1020, :to_port=>1020},
284
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.57/32"}], :ip_protocol=>"tcp", :from_port=>1021, :to_port=>1023},
285
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.58/32"}], :ip_protocol=>"tcp", :from_port=>1024, :to_port=>1024},
286
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.58/32"}], :ip_protocol=>"tcp", :from_port=>1025, :to_port=>1025},
287
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.58/32"}], :ip_protocol=>"tcp", :from_port=>1125, :to_port=>1125},
288
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1200, :to_port=>1200},
289
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1201, :to_port=>1201},
290
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1202, :to_port=>1202},
291
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1203, :to_port=>1203},
292
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1206, :to_port=>1206},
293
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1208, :to_port=>1208},
294
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1209, :to_port=>1209},
295
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1210, :to_port=>1210}
296
+ ]
137
297
  ).and be_idempotent
138
298
  end
139
299
 
140
- it "aws_security_group 'test_sg' with inbound and outbound rules allowing all ports works when protocol specified" do
300
+ it "can specify rules as a hash" do
141
301
  expect_recipe {
142
- aws_security_group 'test_sg' do
143
- vpc 'test_vpc'
144
- inbound_rules('0.0.0.0/0' => { port_range: -1..-1, protocol: -1 })
145
- outbound_rules({ port_range: -1..-1, protocol: -1 } => '0.0.0.0/0')
146
- end
302
+ aws_security_group 'test_sg' do
303
+ # We need to define a list of ports and its easier to use a method than
304
+ # have to add a new number when changing this test
305
+ def counter()
306
+ @ip_counter ||= 0
307
+ @ip_counter += 1
308
+ end
309
+
310
+ vpc 'test_vpc'
311
+ inbound_rules([
312
+ { sources: "10.0.0.#{counter}/32", port_range: -1..-1, protocol: -1 },
313
+ { sources: "10.0.0.#{counter}/32", port: -1, protocol: -1 },
314
+ { sources: "10.0.0.#{counter}/32", port: 1002, protocol: -1 },
315
+ { sources: "10.0.0.#{counter}/32", ports: 1003..1003, protocol: -1 },
316
+ { sources: "10.0.0.#{counter}/32", port_range: 1004..1005, protocol: -1 },
317
+ { sources: "10.0.0.#{counter}/32", port_range: [1006, 1007, 1108], protocol: -1 },
318
+ # If the protocol isn't `-1` and you don't specify all the ports
319
+ # aws wants `port_range` to be nil
320
+ { sources: "10.0.0.#{counter}/32", ports: nil, protocol: :tcp },
321
+ { sources: "10.0.0.#{counter}/32", port_range: 0..65535, protocol: :udp },
322
+ { sources: "10.0.0.#{counter}/32", port_range: -1, protocol: :icmp },
323
+ { sources: "10.0.0.#{counter}/32", port_range: 1..2, protocol: :icmp },
324
+ { sources: "10.0.0.#{counter}/32", port_range: 1011, protocol: :any },
325
+ { sources: "10.0.0.#{counter}/32", port_range: 1012, protocol: nil },
326
+ { sources: "10.0.0.#{counter}/32", port: 1013 },
327
+ { sources: "10.0.0.#{counter}/32", port: 1014..1014 },
328
+ { sources: "10.0.0.#{counter}/32", port: [1015, 1016, 1117] },
329
+ { sources: "10.0.0.#{counter}/32", port: :icmp },
330
+ { sources: "10.0.0.#{counter}/32", port: 'tCp' },
331
+ { sources: "10.0.0.#{counter}/32", port: nil },
332
+ { sources: "10.0.0.#{counter}/32", protocol: -1 },
333
+ { sources: "10.0.0.#{counter}/32", protocol: :any },
334
+ { sources: "10.0.0.#{counter}/32", protocol: 'UDP' },
335
+ { sources: "10.0.0.#{counter}/32", protocol: nil },
336
+ { sources: "10.0.0.#{counter}/32", port_range: 1020 },
337
+ { sources: "10.0.0.#{counter}/32", port_range: 1021..1023 },
338
+ { sources: "10.0.0.#{counter}/32", port_range: [1024, 1025, 1125] },
339
+ { sources: "10.0.0.#{counter}/32", port_range: :icmp },
340
+ { sources: "10.0.0.#{counter}/32", port_range: 'Icmp' },
341
+ { sources: "10.0.0.#{counter}/32", port_range: :tcp },
342
+ { sources: "10.0.0.#{counter}/32", port_range: 'UDP' },
343
+ { sources: "10.0.0.#{counter}/32", port_range: nil },
344
+ { sources: "10.0.0.#{counter}/32", port_range: -1 },
345
+ { sources: "10.0.0.#{counter}/32", port_range: :"-1" },
346
+ { sources: ["10.0.0.#{counter}/32", "10.0.0.#{counter}/32"], port_range: :all },
347
+ { sources: 'test_security_group', port: 1200 },
348
+ { sources: test_security_group.aws_object.id, port: 1201 },
349
+ { sources: test_security_group.aws_object, port: 1202 },
350
+ { sources: test_security_group, port: 1203 },
351
+ # cannot get the ID from the v1 api object
352
+ #testloadbalancer.aws_object.id => 1205,
353
+ { sources: testloadbalancer.aws_object, port: 1206 },
354
+ # Cannot specify a LoadBalancer resource, only AwsLoadBalancer
355
+ #testloadbalancer => 1207,
356
+ { sources: {group_name: 'test_security_group'}, port: 1208 },
357
+ { sources: {load_balancer: 'testloadbalancer'}, port: 1209 },
358
+ { sources: {security_group: 'test_security_group'}, port: 1210 },
359
+ ])
360
+ outbound_rules([
361
+ { port_range: -1..-1, protocol: -1, destinations: "10.0.0.#{counter}/32" },
362
+ { port: -1, protocol: -1, destinations: "10.0.0.#{counter}/32" },
363
+ { port: 1002, protocol: -1, destinations: "10.0.0.#{counter}/32" },
364
+ { ports: 1003..1003, protocol: -1, destinations: "10.0.0.#{counter}/32" },
365
+ { port_range: 1004..1005, protocol: -1, destinations: "10.0.0.#{counter}/32" },
366
+ { port_range: [1006, 1007, 1108], protocol: -1, destinations: "10.0.0.#{counter}/32" },
367
+ # If the protocol isn't `-1` and you don't specify all the ports
368
+ # aws wants `port_range` to be nil{ ports: nil, protocol: :tcp } => "10.0.0.#{counter}/32",
369
+ { port_range: 0..65535, protocol: :udp, destinations: "10.0.0.#{counter}/32" },
370
+ { port_range: -1, protocol: :icmp, destinations: "10.0.0.#{counter}/32" },
371
+ { port_range: 1..2, protocol: :icmp, destinations: "10.0.0.#{counter}/32" },
372
+ { port_range: 1011, protocol: :any, destinations: "10.0.0.#{counter}/32" },
373
+ { port_range: 1012, protocol: nil, destinations: "10.0.0.#{counter}/32" },
374
+ { port: 1013, destinations: "10.0.0.#{counter}/32" },
375
+ { port: 1014..1014, destinations: "10.0.0.#{counter}/32" },
376
+ { port: [1015, 1016, 1117], destinations: "10.0.0.#{counter}/32" },
377
+ { port: :icmp, destinations: "10.0.0.#{counter}/32" },
378
+ { port: 'tCp', destinations: "10.0.0.#{counter}/32" },
379
+ { port: nil, destinations: "10.0.0.#{counter}/32" },
380
+ { protocol: -1, destinations: "10.0.0.#{counter}/32" },
381
+ { protocol: :any, destinations: "10.0.0.#{counter}/32" },
382
+ { protocol: 'UDP', destinations: "10.0.0.#{counter}/32" },
383
+ { protocol: nil, destinations: "10.0.0.#{counter}/32" },
384
+ { port_range: 1020, destinations: "10.0.0.#{counter}/32" },
385
+ { port_range: 1021..1023, destinations: "10.0.0.#{counter}/32" },
386
+ { port_range: [1024, 1025, 1125], destinations: "10.0.0.#{counter}/32" },
387
+ { port_range: :icmp, destinations: "10.0.0.#{counter}/32" },
388
+ { port_range: 'Icmp', destinations: "10.0.0.#{counter}/32" },
389
+ { port_range: :tcp, destinations: "10.0.0.#{counter}/32" },
390
+ { port_range: 'UDP', destinations: "10.0.0.#{counter}/32" },
391
+ { port_range: nil, destinations: "10.0.0.#{counter}/32" },
392
+ { port_range: -1, destinations: "10.0.0.#{counter}/32" },
393
+ { port_range: :"-1", destinations: "10.0.0.#{counter}/32" },
394
+ { port_range: :all, destinations: ["10.0.0.#{counter}/32", "10.0.0.#{counter}/32"] },
395
+ { port: 1200, destinations: 'test_security_group' },
396
+ { port: 1201, destinations: test_security_group.aws_object.id },
397
+ { port: 1202, destinations: test_security_group.aws_object },
398
+ { port: 1203, destinations: test_security_group },
399
+ # cannot get the ID from the v1 api object
400
+ #{ port: 1205, destinations: testloadbalancer.aws_object.id },
401
+ { port: 1206, destinations: testloadbalancer.aws_object },
402
+ # Cannot specify a LoadBalancer resource, only AwsLoadBalancer
403
+ #{ port: 1207, destinations: testloadbalancer },
404
+ { port: 1208, destinations: {group_name: 'test_security_group'} },
405
+ { port: 1209, destinations: {load_balancer: 'testloadbalancer'} },
406
+ { port: 1210, destinations: {security_group: 'test_security_group'} },
407
+ ])
408
+ end
147
409
  }.to create_an_aws_security_group('test_sg',
148
410
  vpc_id: test_vpc.aws_object.id,
149
- ip_permissions_list: [
150
- { groups: [], ip_ranges: [{cidr_ip: "0.0.0.0/0"}], ip_protocol: "-1"}
411
+ ip_permissions_list: Set[
412
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.1/32"}, {:cidr_ip=>"10.0.0.11/32"}, {:cidr_ip=>"10.0.0.19/32"}, {:cidr_ip=>"10.0.0.2/32"}, {:cidr_ip=>"10.0.0.20/32"}, {:cidr_ip=>"10.0.0.3/32"}, {:cidr_ip=>"10.0.0.32/32"}, {:cidr_ip=>"10.0.0.33/32"}, {:cidr_ip=>"10.0.0.34/32"}, {:cidr_ip=>"10.0.0.4/32"}, {:cidr_ip=>"10.0.0.5/32"}, {:cidr_ip=>"10.0.0.6/32"}], :ip_protocol=>"-1"},
413
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.17/32"}, {:cidr_ip=>"10.0.0.18/32"}, {:cidr_ip=>"10.0.0.22/32"}, {:cidr_ip=>"10.0.0.28/32"}, {:cidr_ip=>"10.0.0.30/32"}, {:cidr_ip=>"10.0.0.31/32"}, {:cidr_ip=>"10.0.0.7/32"}], :ip_protocol=>"tcp", :from_port=>0, :to_port=>0},
414
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.8/32"}], :ip_protocol=>"udp", :from_port=>0, :to_port=>65535},
415
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.9/32"}], :ip_protocol=>"icmp", :from_port=>-1, :to_port=>-1},
416
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.10/32"}], :ip_protocol=>"icmp", :from_port=>1, :to_port=>2},
417
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.12/32"}], :ip_protocol=>"tcp", :from_port=>1012, :to_port=>1012},
418
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.13/32"}], :ip_protocol=>"tcp", :from_port=>1013, :to_port=>1013},
419
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.14/32"}], :ip_protocol=>"tcp", :from_port=>1014, :to_port=>1014},
420
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.15/32"}], :ip_protocol=>"tcp", :from_port=>1117, :to_port=>1117},
421
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.15/32"}], :ip_protocol=>"tcp", :from_port=>1015, :to_port=>1015},
422
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.15/32"}], :ip_protocol=>"tcp", :from_port=>1016, :to_port=>1016},
423
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.16/32"}, {:cidr_ip=>"10.0.0.26/32"}, {:cidr_ip=>"10.0.0.27/32"}], :ip_protocol=>"icmp", :from_port=>0, :to_port=>0},
424
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.21/32"}, {:cidr_ip=>"10.0.0.29/32"}], :ip_protocol=>"udp", :from_port=>0, :to_port=>0},
425
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.23/32"}], :ip_protocol=>"tcp", :from_port=>1020, :to_port=>1020},
426
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.24/32"}], :ip_protocol=>"tcp", :from_port=>1021, :to_port=>1023},
427
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.25/32"}], :ip_protocol=>"tcp", :from_port=>1024, :to_port=>1024},
428
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.25/32"}], :ip_protocol=>"tcp", :from_port=>1025, :to_port=>1025},
429
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.25/32"}], :ip_protocol=>"tcp", :from_port=>1125, :to_port=>1125},
430
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1200, :to_port=>1200},
431
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1201, :to_port=>1201},
432
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1202, :to_port=>1202},
433
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1203, :to_port=>1203},
434
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1206, :to_port=>1206},
435
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1208, :to_port=>1208},
436
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1209, :to_port=>1209},
437
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1210, :to_port=>1210}
151
438
  ],
152
- ip_permissions_list_egress: [{ groups: [], ip_ranges: [{cidr_ip: "0.0.0.0/0"}], ip_protocol: "-1"}]
439
+ ip_permissions_list_egress: Set[
440
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.35/32"}, {:cidr_ip=>"10.0.0.36/32"}, {:cidr_ip=>"10.0.0.37/32"}, {:cidr_ip=>"10.0.0.38/32"}, {:cidr_ip=>"10.0.0.39/32"}, {:cidr_ip=>"10.0.0.40/32"}, {:cidr_ip=>"10.0.0.44/32"}, {:cidr_ip=>"10.0.0.52/32"}, {:cidr_ip=>"10.0.0.53/32"}, {:cidr_ip=>"10.0.0.65/32"}, {:cidr_ip=>"10.0.0.66/32"}, {:cidr_ip=>"10.0.0.67/32"}], :ip_protocol=>"-1"},
441
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.41/32"}], :ip_protocol=>"udp", :from_port=>0, :to_port=>65535},
442
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.42/32"}], :ip_protocol=>"icmp", :from_port=>-1, :to_port=>-1},
443
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.43/32"}], :ip_protocol=>"icmp", :from_port=>1, :to_port=>2},
444
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.45/32"}], :ip_protocol=>"tcp", :from_port=>1012, :to_port=>1012},
445
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.46/32"}], :ip_protocol=>"tcp", :from_port=>1013, :to_port=>1013},
446
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.47/32"}], :ip_protocol=>"tcp", :from_port=>1014, :to_port=>1014},
447
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.48/32"}], :ip_protocol=>"tcp", :from_port=>1015, :to_port=>1015},
448
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.48/32"}], :ip_protocol=>"tcp", :from_port=>1016, :to_port=>1016},
449
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.48/32"}], :ip_protocol=>"tcp", :from_port=>1117, :to_port=>1117},
450
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.49/32"}, {:cidr_ip=>"10.0.0.59/32"}, {:cidr_ip=>"10.0.0.60/32"}], :ip_protocol=>"icmp", :from_port=>0, :to_port=>0},
451
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.50/32"}, {:cidr_ip=>"10.0.0.51/32"}, {:cidr_ip=>"10.0.0.55/32"}, {:cidr_ip=>"10.0.0.61/32"}, {:cidr_ip=>"10.0.0.63/32"}, {:cidr_ip=>"10.0.0.64/32"}], :ip_protocol=>"tcp", :from_port=>0, :to_port=>0},
452
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.54/32"}, {:cidr_ip=>"10.0.0.62/32"}], :ip_protocol=>"udp", :from_port=>0, :to_port=>0},
453
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.56/32"}], :ip_protocol=>"tcp", :from_port=>1020, :to_port=>1020},
454
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.57/32"}], :ip_protocol=>"tcp", :from_port=>1021, :to_port=>1023},
455
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.58/32"}], :ip_protocol=>"tcp", :from_port=>1024, :to_port=>1024},
456
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.58/32"}], :ip_protocol=>"tcp", :from_port=>1025, :to_port=>1025},
457
+ {:groups=>[], :ip_ranges=>Set[{:cidr_ip=>"10.0.0.58/32"}], :ip_protocol=>"tcp", :from_port=>1125, :to_port=>1125},
458
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1200, :to_port=>1200},
459
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1201, :to_port=>1201},
460
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1202, :to_port=>1202},
461
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1203, :to_port=>1203},
462
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1206, :to_port=>1206},
463
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1208, :to_port=>1208},
464
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1209, :to_port=>1209},
465
+ {:groups=>[{:group_id=>test_security_group.aws_object.id}], :ip_ranges=>[], :ip_protocol=>"tcp", :from_port=>1210, :to_port=>1210}
466
+ ]
153
467
  ).and be_idempotent
154
468
  end
155
469
  end
@@ -302,9 +302,11 @@ describe Chef::Resource::LoadBalancer do
302
302
  })
303
303
  machines ['test_load_balancer_machine1', test_load_balancer_machine2.aws_object.id]
304
304
  end
305
- }.to create_an_aws_load_balancer('test-load-balancer',
306
- :instances => [{id: test_load_balancer_machine1.aws_object.id}, {id: test_load_balancer_machine2.aws_object.id}]
307
- ).and be_idempotent
305
+ }.to create_an_aws_load_balancer('test-load-balancer') { |aws_object|
306
+ instances = aws_object.instances
307
+ ids = instances.map {|i| i.id}
308
+ expect(ids.to_set).to eq([test_load_balancer_machine1.aws_object.id, test_load_balancer_machine2.aws_object.id].to_set)
309
+ }.and be_idempotent
308
310
  end
309
311
 
310
312
  context "with an existing load_balancer with machine1 attached" do
@@ -7,7 +7,8 @@ describe Chef::Resource::MachineImage do
7
7
  with_aws "with a VPC and a public subnet" do
8
8
  before :all do
9
9
  chef_config[:log_level] = :warn
10
- Chef::Config.chef_provisioning[:machine_max_wait_time] = 240
10
+ chef_config[:include_output_after_example] = true
11
+ Chef::Config.chef_provisioning[:machine_max_wait_time] = 300
11
12
  Chef::Config.chef_provisioning[:image_max_wait_time] = 600
12
13
  end
13
14
 
@@ -21,6 +22,9 @@ describe Chef::Resource::MachineImage do
21
22
  subnet_id: 'test_public_subnet',
22
23
  key_name: 'test_key_pair',
23
24
  instance_type: 'm3.medium'
25
+ },
26
+ ssh_options: {
27
+ timeout: 60
24
28
  }
25
29
  end
26
30
  }.to create_an_aws_image('test_machine_image',
@@ -36,6 +40,9 @@ describe Chef::Resource::MachineImage do
36
40
  subnet_id: 'test_public_subnet',
37
41
  key_name: 'test_key_pair',
38
42
  instance_type: 'm3.medium'
43
+ },
44
+ ssh_options: {
45
+ timeout: 60
39
46
  }
40
47
  end
41
48
  }
@@ -70,6 +77,9 @@ describe Chef::Resource::MachineImage do
70
77
  machine_options bootstrap_options: {
71
78
  key_name: 'test_key_pair',
72
79
  instance_type: 'm3.medium'
80
+ },
81
+ ssh_options: {
82
+ timeout: 60
73
83
  }
74
84
  aws_tags key1: "value"
75
85
  end
@@ -86,6 +96,9 @@ describe Chef::Resource::MachineImage do
86
96
  machine_options bootstrap_options: {
87
97
  key_name: 'test_key_pair',
88
98
  instance_type: 'm3.medium'
99
+ },
100
+ ssh_options: {
101
+ timeout: 60
89
102
  }
90
103
  aws_tags key1: "value"
91
104
  end
@@ -188,10 +188,14 @@ describe Chef::Resource::Machine do
188
188
 
189
189
  context "with a placement group" do
190
190
  before(:context) {
191
- driver.ec2_client.create_placement_group({
192
- group_name: "agroup",
193
- strategy: "cluster"
194
- })
191
+ begin
192
+ driver.ec2_client.create_placement_group({
193
+ group_name: "agroup",
194
+ strategy: "cluster"
195
+ })
196
+ rescue Aws::EC2::Errors::InvalidPlacementGroupDuplicate
197
+ # We don't need to create it because it already exists
198
+ end
195
199
  }
196
200
 
197
201
  # Must do after the context so we have waited for the instance to terminate
@@ -293,6 +297,46 @@ describe Chef::Resource::Machine do
293
297
  ).and be_idempotent
294
298
  end
295
299
 
300
+ context "with an existing machine", :super_slow do
301
+ machine 'test_machine' do
302
+ machine_options bootstrap_options: {
303
+ subnet_id: 'test_public_subnet',
304
+ key_name: 'test_key_pair'
305
+ }
306
+ action :allocate
307
+ end
308
+
309
+ it "stops the machine with the :stop action" do
310
+ expect_recipe {
311
+ machine 'test_machine' do
312
+ action :stop
313
+ end
314
+ }.to update_an_aws_instance('test_machine',
315
+ state: {:name => "stopped"}
316
+ ).and be_idempotent
317
+ end
318
+
319
+ it "starts a machine that has been stopped" do
320
+ expect_recipe {
321
+ machine 'test_machine' do
322
+ action :stop
323
+ end
324
+ machine 'test_machine' do
325
+ action :ready
326
+ end
327
+ }.to update_an_aws_instance('test_machine',
328
+ state: {:name => "running"}
329
+ )
330
+ end
331
+ end
332
+
333
+ it "doesn't create a machine if the initial action is :stop", :super_slow do
334
+ expect_recipe {
335
+ machine 'test_machine' do
336
+ action :stop
337
+ end
338
+ }.not_to create_an_aws_instance('test_machine')
339
+ end
296
340
  end
297
341
 
298
342
  with_aws "Without a VPC" do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chef-provisioning-aws
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.1
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Ewart
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-13 00:00:00.000000000 Z
11
+ date: 2015-10-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chef-provisioning
@@ -190,6 +190,7 @@ files:
190
190
  - LICENSE
191
191
  - README.md
192
192
  - Rakefile
193
+ - chef-provisioning-aws.gemspec
193
194
  - lib/chef/provider/aws_auto_scaling_group.rb
194
195
  - lib/chef/provider/aws_cache_cluster.rb
195
196
  - lib/chef/provider/aws_cache_replication_group.rb