chef-provisioning-aws 1.5.1 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
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