stemcell 0.12.0 → 0.13.1

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
- SHA1:
3
- metadata.gz: d0a73c0c28344f526396892ffde6de0054696d7f
4
- data.tar.gz: 3286ce5584f761e5e643f9fe02bd575f9199e651
2
+ SHA256:
3
+ metadata.gz: 9942211d9334ce09b4a56299f2bc7e3e903d57eb871a60a8a1228c549e6b1407
4
+ data.tar.gz: 3e70bbdc1434124922c4be3cfb29e6842d6cda8210a1555fe3c36e4887740a11
5
5
  SHA512:
6
- metadata.gz: 00ddd6ab1066baf755627d945f0fc033457f9256f891176a5af5b1b0d259fc93885d08a1d5b12cce4cbe42733be0b8af36ae6003fab521d7535cd00dd9da57e8
7
- data.tar.gz: 4e09e64bba35df73ec82622889863d3456b162a6d9405954f02bb0087709bbf9a0036d052d543823871ed712d0c6171222a2bddbd7ab9e94eb9bdf7f351a036b
6
+ metadata.gz: c4f0a32c8fe858b23bd3ddbbb30ca752a0b23c0a2782d9fd0cf56d9cda0e344bdaa3c2361b1df9f4d5f5413ca88e15c714c868ee2efaa1b304dd74d248601fdb
7
+ data.tar.gz: a9fb4751d0fe25b94f4c47785da168a9e0e909464d0354461adc8db5d01487d5ea696ebcbc79e74267b6ccd114a794a5e5d13ed90bd6b831a20c3bb5ae5b4906
data/.travis.yml CHANGED
@@ -5,5 +5,6 @@ rvm:
5
5
  - 2.1.2
6
6
  - 2.2.4
7
7
  - 2.3.1
8
+ - 2.6.8
8
9
  before_install:
9
- - gem install bundler
10
+ - gem install bundler -v 1.16.3
data/CHANGELOG.md CHANGED
@@ -1,3 +1,19 @@
1
+ # 0.13.1
2
+ - Support for specifying --cpu-options
3
+
4
+ # 0.13.0
5
+ - Migrate to AWS SDK to v3
6
+ - Drop support for ClassicLink
7
+ - Removed `necrosis` script
8
+
9
+ # 0.12.2
10
+ - Support for using a custom EC2 endpoint
11
+
12
+ # 0.12.1
13
+ - Add support for Amazon Linux to the default bootstrap script
14
+ - Allow setting backing_store options per region
15
+ - Display private ip for launched instances
16
+
1
17
  # 0.12.0
2
18
  - Require Nokogiri ~> 1.8.2 due to vulnerability CVE-2017-15412
3
19
  - Require ruby version >= 2.1 for Nokogiri compatibility
data/README.md CHANGED
@@ -77,10 +77,10 @@ $ stemcell $your_chef_role --tail
77
77
 
78
78
  ### Terminating:
79
79
 
80
- To terminate, use the necrosis command and pass a space separated list of instance ids:
80
+ To terminate, use the AWS CLI and pass a space separated list of instance ids:
81
81
 
82
82
  ```bash
83
- $ necrosis i-12345678 i-12345679 i-12345670
83
+ $ aws ec2 terminate-instances --instance-ids i-12345678 i-12345679 i-12345670
84
84
  ```
85
85
 
86
86
  ## Automation ##
@@ -9,10 +9,14 @@
9
9
 
10
10
  "backing_store": {
11
11
  "ebs": {
12
- "image_id": "ami-23d9a94a"
12
+ "us-east-1": {
13
+ "image_id": "ami-23d9a94a"
14
+ }
13
15
  },
14
16
  "instance_store": {
15
- "image_id": "ami-d9d6a6b0"
17
+ "us-east-1": {
18
+ "image_id": "ami-d9d6a6b0"
19
+ }
16
20
  }
17
21
  },
18
22
 
@@ -132,6 +132,7 @@ module Stemcell
132
132
  # comma-separated list when presented as defaults.
133
133
  pd['security_groups'] &&= pd['security_groups'].join(',')
134
134
  pd['tags'] &&= pd['tags'].to_a.map { |p| p.join('=') }.join(',')
135
+ pd['cpu_options'] &&= pd['cpu_options'].to_a.map { |p| p.join('=') }.join(',')
135
136
  pd['chef_cookbook_attributes'] &&= pd['chef_cookbook_attributes'].join(',')
136
137
  end
137
138
 
@@ -1,4 +1,5 @@
1
- require 'aws-sdk-v1'
1
+ require 'aws-sdk-ec2'
2
+ require 'base64'
2
3
  require 'logger'
3
4
  require 'erb'
4
5
  require 'set'
@@ -30,6 +31,7 @@ module Stemcell
30
31
  'chef_environment',
31
32
  'chef_data_bag_secret',
32
33
  'chef_data_bag_secret_path',
34
+ 'cpu_options',
33
35
  'git_branch',
34
36
  'git_key',
35
37
  'git_origin',
@@ -48,7 +50,6 @@ module Stemcell
48
50
  'security_groups',
49
51
  'security_group_ids',
50
52
  'tags',
51
- 'classic_link',
52
53
  'iam_role',
53
54
  'ebs_optimized',
54
55
  'termination_protection',
@@ -75,6 +76,7 @@ module Stemcell
75
76
 
76
77
  @region = opts['region']
77
78
  @vpc_id = opts['vpc_id']
79
+ @ec2_endpoint = opts['ec2_endpoint']
78
80
  @aws_access_key = opts['aws_access_key']
79
81
  @aws_secret_key = opts['aws_secret_key']
80
82
  @aws_session_token = opts['aws_session_token']
@@ -89,7 +91,7 @@ module Stemcell
89
91
  opts['git_key'] = try_file(opts['git_key'])
90
92
  opts['chef_data_bag_secret'] = try_file(opts['chef_data_bag_secret'])
91
93
 
92
- # generate tags and merge in any that were specefied as inputs
94
+ # generate tags and merge in any that were specified as inputs
93
95
  tags = {
94
96
  'Name' => "#{opts['chef_role']}-#{opts['chef_environment']}",
95
97
  'Group' => "#{opts['chef_role']}-#{opts['chef_environment']}",
@@ -105,31 +107,38 @@ module Stemcell
105
107
  :image_id => opts['image_id'],
106
108
  :instance_type => opts['instance_type'],
107
109
  :key_name => opts['key_name'],
108
- :count => opts['count'],
110
+ :min_count => opts['count'],
111
+ :max_count => opts['count'],
109
112
  }
110
113
 
114
+
115
+ # Associate Public IP can only bet set on network_interfaces, and if present
116
+ # security groups and subnet should be set on the interface. VPC-only.
117
+ # Primary network interface
118
+ network_interface = {
119
+ device_index: 0,
120
+ }
121
+ launch_options[:network_interfaces] = [network_interface]
122
+
111
123
  if opts['security_group_ids'] && !opts['security_group_ids'].empty?
112
- launch_options[:security_group_ids] = opts['security_group_ids']
124
+ network_interface[:groups] = opts['security_group_ids']
113
125
  end
114
126
 
115
127
  if opts['security_groups'] && !opts['security_groups'].empty?
116
- if @vpc_id
117
- # convert sg names to sg ids as VPC only accepts ids
118
- security_group_ids = get_vpc_security_group_ids(@vpc_id, opts['security_groups'])
119
- launch_options[:security_group_ids] ||= []
120
- launch_options[:security_group_ids].concat(security_group_ids)
121
- else
122
- launch_options[:security_groups] = opts['security_groups']
123
- end
128
+ # convert sg names to sg ids as VPC only accepts ids
129
+ security_group_ids = get_vpc_security_group_ids(@vpc_id, opts['security_groups'])
130
+ network_interface[:groups] ||= []
131
+ network_interface[:groups].concat(security_group_ids)
124
132
  end
125
133
 
134
+ launch_options[:placement] = placement = {}
126
135
  # specify availability zone (optional)
127
136
  if opts['availability_zone']
128
- launch_options[:availability_zone] = opts['availability_zone']
137
+ placement[:availability_zone] = opts['availability_zone']
129
138
  end
130
139
 
131
140
  if opts['subnet']
132
- launch_options[:subnet] = opts['subnet']
141
+ network_interface[:subnet_id] = opts['subnet']
133
142
  end
134
143
 
135
144
  if opts['private_ip_address']
@@ -137,23 +146,23 @@ module Stemcell
137
146
  end
138
147
 
139
148
  if opts['dedicated_tenancy']
140
- launch_options[:dedicated_tenancy] = opts['dedicated_tenancy']
149
+ placement[:tenancy] = 'dedicated'
141
150
  end
142
151
 
143
152
  if opts['associate_public_ip_address']
144
- launch_options[:associate_public_ip_address] = opts['associate_public_ip_address']
153
+ network_interface[:associate_public_ip_address] = opts['associate_public_ip_address']
145
154
  end
146
155
 
147
156
  # specify IAM role (optional)
148
157
  if opts['iam_role']
149
- launch_options[:iam_instance_profile] = opts['iam_role']
158
+ launch_options[:iam_instance_profile] = {
159
+ name: opts['iam_role']
160
+ }
150
161
  end
151
162
 
152
163
  # specify placement group (optional)
153
164
  if opts['placement_group']
154
- launch_options[:placement] = {
155
- :group_name => opts['placement_group'],
156
- }
165
+ placement[:group_name] = opts['placement_group']
157
166
  end
158
167
 
159
168
  # specify an EBS-optimized instance (optional)
@@ -170,6 +179,11 @@ module Stemcell
170
179
  launch_options[:block_device_mappings] = opts['block_device_mappings']
171
180
  end
172
181
 
182
+ # specify cpu options (optional)
183
+ if opts['cpu_options']
184
+ launch_options[:cpu_options] = opts['cpu_options']
185
+ end
186
+
173
187
  # specify ephemeral block device mappings (optional)
174
188
  if opts['ephemeral_devices']
175
189
  launch_options[:block_device_mappings] ||= []
@@ -181,35 +195,31 @@ module Stemcell
181
195
  end
182
196
  end
183
197
 
198
+ if opts['termination_protection']
199
+ launch_options[:disable_api_termination] = true
200
+ end
201
+
184
202
  # generate user data script to bootstrap instance, include in launch
185
203
  # options UNLESS we have manually set the user-data (ie. for ec2admin)
186
- launch_options[:user_data] = opts.fetch('user_data', render_template(opts))
204
+ launch_options[:user_data] = Base64.encode64(opts.fetch('user_data', render_template(opts)))
205
+
206
+ # add tags to launch options so we don't need to make a separate CreateTags call
207
+ launch_options[:tag_specifications] = [{
208
+ resource_type: 'instance',
209
+ tags: tags.map { |k, v| { key: k, value: v } }
210
+ }]
187
211
 
188
212
  # launch instances
189
213
  instances = do_launch(launch_options)
190
214
 
191
215
  # everything from here on out must succeed, or we kill the instances we just launched
192
216
  begin
193
- # set tags on all instances launched
194
- set_tags(instances, tags)
195
- @log.info "sent ec2 api tag requests successfully"
196
-
197
- # link to classiclink
198
- unless @vpc_id
199
- set_classic_link(instances, opts['classic_link'])
200
- @log.info "successfully applied classic link settings (if any)"
201
- end
202
-
203
- # turn on termination protection
204
- # we do this now to make sure all other settings worked
205
- if opts['termination_protection']
206
- enable_termination_protection(instances)
207
- @log.info "successfully enabled termination protection"
208
- end
209
-
210
217
  # wait for aws to report instance stats
211
218
  if opts.fetch('wait', true)
212
- wait(instances)
219
+ instance_ids = instances.map(&:instance_id)
220
+ @log.info "Waiting up to #{MAX_RUNNING_STATE_WAIT_TIME} seconds for #{instances.count} " \
221
+ "instance(s): (#{instance_ids})"
222
+ instances = wait(instance_ids)
213
223
  print_run_info(instances)
214
224
  @log.info "launched instances successfully"
215
225
  end
@@ -226,19 +236,18 @@ module Stemcell
226
236
  return instances
227
237
  end
228
238
 
229
- def kill(instances, opts={})
230
- return if !instances || instances.empty?
239
+ def kill(instance_ids, opts={})
240
+ return if !instance_ids || instance_ids.empty?
231
241
 
232
- errors = run_batch_operation(instances) do |instance|
233
- begin
234
- @log.warn "Terminating instance #{instance.id}"
235
- instance.terminate
236
- nil # nil == success
237
- rescue AWS::EC2::Errors::InvalidInstanceID::NotFound => e
238
- opts[:ignore_not_found] ? nil : e
239
- end
240
- end
241
- check_errors(:kill, instances.map(&:id), errors)
242
+ @log.warn "Terminating instances #{instance_ids}"
243
+ ec2.terminate_instances(instance_ids: instance_ids)
244
+ nil # nil == success
245
+ rescue Aws::EC2::Errors::InvalidInstanceIDNotFound => e
246
+ raise unless opts[:ignore_not_found]
247
+
248
+ invalid_ids = e.message.scan(/i-[a-z0-9]+/)
249
+ instance_ids -= invalid_ids
250
+ retry unless instance_ids.empty? || invalid_ids.empty? # don't retry if we couldn't find any instance ids
242
251
  end
243
252
 
244
253
  # this is made public for ec2admin usage
@@ -248,7 +257,7 @@ module Stemcell
248
257
  erb_template = ERB.new(template_file)
249
258
  last_bootstrap_line = LAST_BOOTSTRAP_LINE
250
259
  generated_template = erb_template.result(binding)
251
- @log.debug "genereated template is #{generated_template}"
260
+ @log.debug "generated template is #{generated_template}"
252
261
  return generated_template
253
262
  end
254
263
 
@@ -258,22 +267,23 @@ module Stemcell
258
267
  puts "\nhere is the info for what's launched:"
259
268
  instances.each do |instance|
260
269
  puts "\tinstance_id: #{instance.instance_id}"
261
- puts "\tpublic ip: #{instance.public_ip_address}"
270
+ puts "\tpublic ip: #{instance.public_ip_address || 'none'}"
271
+ puts "\tprivate ip: #{instance.private_ip_address || 'none'}"
262
272
  puts
263
273
  end
264
274
  puts "install logs will be in /var/log/init and /var/log/init.err"
265
275
  end
266
276
 
267
- def wait(instances)
268
- @log.info "Waiting up to #{MAX_RUNNING_STATE_WAIT_TIME} seconds for #{instances.count} " \
269
- "instance(s): (#{instances.inspect})"
270
-
271
- times_out_at = Time.now + MAX_RUNNING_STATE_WAIT_TIME
272
- until instances.all?{ |i| i.status == :running }
273
- wait_time_expire_or_sleep(times_out_at)
277
+ def wait(instance_ids)
278
+ started_at = Time.now
279
+ result = ec2.wait_until(:instance_running, instance_ids: instance_ids) do |w|
280
+ w.max_attempts = nil
281
+ w.delay = RUNNING_STATE_WAIT_SLEEP_TIME
282
+ w.before_wait do |attempts, response|
283
+ throw :failure if Time.now - started_at > MAX_RUNNING_STATE_WAIT_TIME
284
+ end
274
285
  end
275
-
276
- @log.info "all instances in running state"
286
+ result.map { |page| page.reservations.map(&:instances) }.flatten
277
287
  end
278
288
 
279
289
  def verify_required_options(params, required_options)
@@ -289,35 +299,22 @@ module Stemcell
289
299
  def do_launch(opts={})
290
300
  @log.debug "about to launch instance(s) with options #{opts}"
291
301
  @log.info "launching instances"
292
- instances = ec2.instances.create(opts)
293
- instances = [instances] unless Array === instances
302
+ instances = ec2.run_instances(opts).instances
294
303
  instances.each do |instance|
295
304
  @log.info "launched instance #{instance.instance_id}"
296
305
  end
297
306
  return instances
298
307
  end
299
308
 
300
- def set_tags(instances=[], tags)
301
- @log.info "setting tags on instance(s)"
302
- errors = run_batch_operation(instances) do |instance|
303
- begin
304
- instance.tags.set(tags)
305
- nil # nil == success
306
- rescue AWS::EC2::Errors::InvalidInstanceID::NotFound => e
307
- e
308
- end
309
- end
310
- check_errors(:set_tags, instances.map(&:id), errors)
311
- end
312
-
313
309
  # Resolve security group names to their ids in the given VPC
314
310
  def get_vpc_security_group_ids(vpc_id, group_names)
315
311
  group_map = {}
316
312
  @log.info "resolving security groups #{group_names} in #{vpc_id}"
317
- vpc = AWS::EC2::VPC.new(vpc_id, :ec2_endpoint => "ec2.#{@region}.amazonaws.com")
318
- vpc.security_groups.each do |sg|
319
- next if sg.vpc_id != vpc_id
320
- group_map[sg.name] = sg.group_id
313
+ ec2.describe_security_groups(filters: [{ name: 'vpc-id', values: [vpc_id] }]).
314
+ each do |response|
315
+ response.security_groups.each do |sg|
316
+ group_map[sg.group_name] = sg.group_id
317
+ end
321
318
  end
322
319
  group_ids = []
323
320
  group_names.each do |sg_name|
@@ -327,129 +324,15 @@ module Stemcell
327
324
  group_ids
328
325
  end
329
326
 
330
- def set_classic_link(left_to_process, classic_link)
331
- return unless classic_link
332
- return unless classic_link['vpc_id']
333
-
334
- security_group_ids = classic_link['security_group_ids'] || []
335
- security_group_names = classic_link['security_groups'] || []
336
- return if security_group_ids.empty? && security_group_names.empty?
337
-
338
- if !security_group_names.empty?
339
- extra_group_ids = get_vpc_security_group_ids(classic_link['vpc_id'], security_group_names)
340
- security_group_ids = security_group_ids + extra_group_ids
341
- end
342
-
343
- @log.info "applying classic link settings on #{left_to_process.count} instance(s)"
344
-
345
- errors = []
346
- processed = []
347
- times_out_at = Time.now + MAX_RUNNING_STATE_WAIT_TIME
348
- until left_to_process.empty?
349
- wait_time_expire_or_sleep(times_out_at)
350
-
351
- # we can only apply classic link when instances are in the running state
352
- # lets apply classiclink as instances become available so we don't wait longer than necessary
353
- recently_running = left_to_process.select{ |inst| inst.status == :running }
354
- left_to_process = left_to_process.reject{ |inst| recently_running.include?(inst) }
355
-
356
- processed += recently_running
357
- errors += run_batch_operation(recently_running) do |instance|
358
- begin
359
- result = ec2.client.attach_classic_link_vpc({
360
- :instance_id => instance.id,
361
- :vpc_id => classic_link['vpc_id'],
362
- :groups => security_group_ids,
363
- })
364
- result.error
365
- rescue StandardError => e
366
- e
367
- end
368
- end
369
- end
370
-
371
- check_errors(:set_classic_link, processed.map(&:id), errors)
372
- end
373
-
374
- def enable_termination_protection(instances)
375
- @log.info "enabling termination protection on instance(s)"
376
- errors = run_batch_operation(instances) do |instance|
377
- begin
378
- resp = ec2.client.modify_instance_attribute({
379
- :instance_id => instance.id,
380
- :disable_api_termination => {
381
- :value => true
382
- }
383
- })
384
- resp.error # returns nil (success) unless there was an error
385
- rescue StandardError => e
386
- e
387
- end
388
- end
389
- check_errors(:enable_termination_protection, instances.map(&:id), errors)
390
- end
391
-
392
327
  # attempt to accept keys as file paths
393
328
  def try_file(opt="")
394
329
  File.read(File.expand_path(opt)) rescue opt
395
330
  end
396
331
 
397
- INITIAL_RETRY_SEC = 1
398
-
399
- # Return a Hash of instance => error. Empty hash indicates "no error"
400
- # for code block:
401
- # - if block returns nil, success
402
- # - if block returns non-nil value (e.g., exception), retry 3 times w/ backoff
403
- # - if block raises exception, fail
404
- def run_batch_operation(instances)
405
- instances.map do |instance|
406
- begin
407
- attempt = 0
408
- result = nil
409
- while attempt < @max_attempts
410
- # sleep idempotently except for the first attempt
411
- sleep(INITIAL_RETRY_SEC * 2 ** attempt) if attempt != 0
412
- result = yield(instance)
413
- break if result.nil? # nil indicates success
414
- attempt += 1
415
- end
416
- result # result for this instance is nil or returned exception
417
- rescue => e
418
- e # result for this instance is caught exception
419
- end
420
- end
421
- end
422
-
423
- def check_errors(operation, instance_ids, errors)
424
- return if errors.all?(&:nil?)
425
- raise IncompleteOperation.new(
426
- operation,
427
- instance_ids,
428
- instance_ids.zip(errors).reject { |i, e| e.nil? }
429
- )
430
- end
431
-
432
332
  def ec2
433
- return @ec2 if @ec2
434
-
435
- # calculate our ec2 url
436
- ec2_url = "ec2.#{@region}.amazonaws.com"
437
-
438
- if @vpc_id
439
- @ec2 = AWS::EC2::VPC.new(@vpc_id, :ec2_endpoint => ec2_url)
440
- else
441
- @ec2 = AWS::EC2.new(:ec2_endpoint => ec2_url)
442
- end
443
-
444
- @ec2
445
- end
446
-
447
- def wait_time_expire_or_sleep(times_out_at)
448
- now = Time.now
449
- if now >= times_out_at
450
- raise TimeoutError, "exceded timeout of #{MAX_RUNNING_STATE_WAIT_TIME} seconds"
451
- else
452
- sleep [RUNNING_STATE_WAIT_SLEEP_TIME, times_out_at - now].min
333
+ @ec2 ||= begin
334
+ opts = @ec2_endpoint ? { endpoint: @ec2_endpoint } : {}
335
+ Aws::EC2::Client.new(opts)
453
336
  end
454
337
  end
455
338
 
@@ -463,7 +346,7 @@ module Stemcell
463
346
  aws_configs.merge!({
464
347
  :session_token => @aws_session_token,
465
348
  }) if @aws_session_token
466
- AWS.config(aws_configs)
349
+ Aws.config.update(aws_configs)
467
350
  end
468
351
  end
469
352
  end
@@ -101,6 +101,7 @@ module Stemcell
101
101
  'region' => options['region'],
102
102
  'vpc_id' => options['vpc_id'],
103
103
  'max_attempts' => options['batch_operation_retries'],
104
+ 'ec2_endpoint' => options['ec2_endpoint'],
104
105
  })
105
106
  # Slice off just the options used for launching.
106
107
  launch_options = {}
@@ -21,10 +21,10 @@ module Stemcell
21
21
  validate_configutation
22
22
  end
23
23
 
24
- def options_for_backing_store(backing_store)
24
+ def options_for_backing_store(backing_store, region)
25
25
  options = backing_store_options[backing_store]
26
26
  raise UnknownBackingStoreError.new(backing_store) if options.nil?
27
- options
27
+ options.fetch(region, options)
28
28
  end
29
29
 
30
30
  def random_az_for_region(region)
@@ -84,9 +84,14 @@ module Stemcell
84
84
  backing_store ||= config.default_options['backing_store']
85
85
  backing_store ||= DEFAULT_BACKING_STORE
86
86
 
87
+ backing_store_region = override_options['region']
88
+ backing_store_region ||= role_options.to_hash['region'] if role_options
89
+ backing_store_region ||= config.default_options['region']
90
+ backing_store_region ||= DEFAULT_OPTIONS['region']
91
+
87
92
  # Step 3: Retrieve the backing store options from the defaults.
88
93
 
89
- backing_store_options = config.options_for_backing_store(backing_store)
94
+ backing_store_options = config.options_for_backing_store(backing_store, backing_store_region)
90
95
  backing_store_options['backing_store'] = backing_store
91
96
 
92
97
  # Step 4: Merge the options together in priority order.
@@ -42,6 +42,12 @@ module Stemcell
42
42
  :env => 'AWS_SESSION_TOKEN',
43
43
  :hide => true
44
44
  },
45
+ {
46
+ :name => 'ec2_endpoint',
47
+ :desc => 'EC2 endpoint',
48
+ :type => String,
49
+ :env => 'EC2_ENDPOINT',
50
+ },
45
51
  {
46
52
  :name => 'region',
47
53
  :desc => "ec2 region to launch in",
@@ -90,24 +96,6 @@ module Stemcell
90
96
  :type => String,
91
97
  :env => 'VPC_ID'
92
98
  },
93
- {
94
- :name => 'classic_link_vpc_id',
95
- :desc => 'VPC ID to which this instance will be classic-linked',
96
- :type => String,
97
- :env => 'CLASSIC_LINK_VPC_ID',
98
- },
99
- {
100
- :name => 'classic_link_security_group_ids',
101
- :desc => 'comma-separated list of security group IDs to link into ClassicLink; not used unless classic_link_vpc_id is set',
102
- :type => String,
103
- :env => 'CLASSIC_LINK_SECURITY_GROUP_IDS',
104
- },
105
- {
106
- :name => 'classic_link_security_groups',
107
- :desc => 'comma-separated list of security groups to link into ClassicLink; not used unless classic_link_vpc_id is set',
108
- :type => String,
109
- :env => 'CLASSIC_LINK_SECURITY_GROUPS',
110
- },
111
99
  {
112
100
  :name => 'subnet',
113
101
  :desc => "VPC subnet for which to launch this instance",
@@ -199,6 +187,12 @@ module Stemcell
199
187
  :type => String,
200
188
  :env => 'CHEF_DATA_BAG_SECRET_PATH'
201
189
  },
190
+ {
191
+ :name => 'cpu_options',
192
+ :desc => "comma-separated list of cpu option key=value pairs",
193
+ :type => String,
194
+ :env => 'CPU_OPTIONS'
195
+ },
202
196
  {
203
197
  :name => 'chef_role',
204
198
  :desc => "chef role of instance to be launched",
@@ -357,6 +351,16 @@ module Stemcell
357
351
  options['tags'] = tags
358
352
  end
359
353
 
354
+ # convert cpu_options from comma separated string to ruby hash
355
+ if options['cpu_options']
356
+ cpu_options = {}
357
+ options['cpu_options'].split(',').each do |cpu_opt|
358
+ key, value = cpu_opt.split('=')
359
+ cpu_options[key] = value
360
+ end
361
+ options['cpu_options'] = cpu_options
362
+ end
363
+
360
364
  # parse block_device_mappings to convert it from the standard CLI format
361
365
  # to the EC2 Ruby API format.
362
366
  # All of this is a bit hard to find so here are some docs links to
@@ -424,17 +428,6 @@ module Stemcell
424
428
  # convert chef_cookbook_attributes from comma separated string to ruby array
425
429
  options['chef_cookbook_attributes'] &&= options['chef_cookbook_attributes'].split(',')
426
430
 
427
- # format the classic link options
428
- if options['classic_link_vpc_id']
429
- options['classic_link']['vpc_id'] = options['classic_link_vpc_id']
430
- end
431
- if options['classic_link_security_group_ids']
432
- options['classic_link']['security_group_ids'] = options['classic_link_security_group_ids'].split(',')
433
- end
434
- if options['classic_link_security_groups']
435
- options['classic_link']['security_groups'] = options['classic_link_security_groups'].split(',')
436
- end
437
-
438
431
  options
439
432
  end
440
433