aerosol 1.6.0 → 1.9.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
- SHA1:
3
- metadata.gz: 5a96e75a7639dbf9316f223618691dd84549339a
4
- data.tar.gz: 477c9f72cb6475f12f7122983f9f78925cced019
2
+ SHA256:
3
+ metadata.gz: 5c51be45f1098f15a79cbab049755110bf351bed1661bb5b28504ab34c613f01
4
+ data.tar.gz: 235972faf898d0cc796cdf0b7de74f05a6c3aa396dc13b9f0f8909fb1229cecb
5
5
  SHA512:
6
- metadata.gz: 86a6bdc81fee94cc1a8288afee120d949483ea541affb17c72818d662e73f5097b8c20155be380166a9cea66c4a16bd7ed90c020fa2d06c36b44bc1d24bc53ed
7
- data.tar.gz: 92ddc9ebeca1dc6119be18aa898f7d0771b32f4dd77380b85af04e5bad9c6e2953be11d10a7b34a5958f930fe58925a26527812f35aa4b8c04b16da43d4a5ef5
6
+ metadata.gz: 5aa215e96061f829d5042d72c56495f0059cb716b12b89386ca84e7b5568b6993d39a18d07e216c90de2af96ba742d5ea588c733e0303d275ffdb16bfb7f8965
7
+ data.tar.gz: 890ced1dce45bcf8ab1de6d60834f78bd881490efd9d7473ada54ac92359a691c53f031959c9cb7e08fb1745c7d9ada0abb84b00913d83e5166cb661c252fdbd
data/.travis.yml CHANGED
@@ -2,10 +2,9 @@ sudo: false
2
2
  dist: trusty
3
3
  language: ruby
4
4
  rvm:
5
- - 1.9.3
6
5
  - 2.0
7
6
  - 2.1
8
7
  - 2.2
9
8
  cache: bundler
10
- before_install: gem install bundler
9
+ before_install: gem install bundler -v 1.17.3
11
10
  script: CI=true bundle exec rake
data/aerosol.gemspec CHANGED
@@ -18,14 +18,17 @@ Gem::Specification.new do |gem|
18
18
  gem.add_dependency 'activerecord', '>= 3.2.0'
19
19
  gem.add_dependency 'clamp', '~> 0.6'
20
20
  gem.add_dependency 'excon'
21
- gem.add_dependency 'aws-sdk', '~> 2.0'
21
+ gem.add_dependency 'aws-sdk-core', '~> 3'
22
+ gem.add_dependency 'aws-sdk-s3', '~> 1'
23
+ gem.add_dependency 'aws-sdk-ec2', '~> 1'
24
+ gem.add_dependency 'aws-sdk-autoscaling', '~> 1'
22
25
  gem.add_dependency 'minigit', '~> 0.0.4'
23
26
  gem.add_dependency 'net-ssh'
24
27
  gem.add_dependency 'net-ssh-gateway'
25
28
  gem.add_dependency 'dockly-util', '~> 0.1.0'
26
29
  gem.add_development_dependency 'cane'
27
30
  gem.add_development_dependency 'pry'
28
- gem.add_development_dependency 'rake'
31
+ gem.add_development_dependency 'rake', '~> 10.0'
29
32
  gem.add_development_dependency 'rspec', '< 3.0'
30
33
  gem.add_development_dependency 'webmock'
31
34
  gem.add_development_dependency 'vcr'
data/lib/aerosol.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  require 'yaml'
2
- require 'aws-sdk'
2
+ require 'aws-sdk-autoscaling'
3
+ require 'aws-sdk-core'
4
+ require 'aws-sdk-s3'
5
+ require 'aws-sdk-ec2'
3
6
  require 'dockly/util'
4
7
  require 'base64'
5
8
 
@@ -10,6 +13,7 @@ module Aerosol
10
13
  require 'aerosol/util'
11
14
  require 'aerosol/aws_model'
12
15
  require 'aerosol/launch_configuration'
16
+ require 'aerosol/launch_template'
13
17
  require 'aerosol/auto_scaling'
14
18
  require 'aerosol/instance'
15
19
  require 'aerosol/connection'
@@ -58,6 +62,7 @@ module Aerosol
58
62
  :auto_scalings => Aerosol::AutoScaling.instances,
59
63
  :deploys => Aerosol::Deploy.instances,
60
64
  :launch_configurations => Aerosol::LaunchConfiguration.instances,
65
+ :launch_templates => Aerosol::LaunchTemplate.instances,
61
66
  :sshs => Aerosol::Connection.instances,
62
67
  :envs => Aerosol::Env.instances
63
68
  }
@@ -67,6 +72,7 @@ module Aerosol
67
72
  :auto_scaling => Aerosol::AutoScaling,
68
73
  :deploy => Aerosol::Deploy,
69
74
  :launch_configuration => Aerosol::LaunchConfiguration,
75
+ :launch_template => Aerosol::LaunchTemplate,
70
76
  :ssh => Aerosol::Connection,
71
77
  :env => Aerosol::Env
72
78
  }.each do |method, klass|
@@ -79,15 +85,15 @@ module Aerosol
79
85
  end
80
86
  end
81
87
 
82
- [:auto_scalings, :deploys, :launch_configurations, :sshs, :envs].each do |method|
88
+ [:auto_scalings, :deploys, :launch_configurations, :launch_templates, :sshs, :envs].each do |method|
83
89
  define_method(method) do
84
90
  inst[method]
85
91
  end
86
92
  end
87
93
 
88
94
  module_function :inst, :load_inst, :setup, :load_file, :load_file=,
89
- :auto_scaling, :launch_configuration, :deploy, :ssh, :git_sha,
90
- :auto_scalings, :launch_configurations, :deploys, :sshs,
95
+ :auto_scaling, :launch_configuration, :launch_template, :deploy, :ssh, :git_sha,
96
+ :auto_scalings, :launch_configurations, :launch_templates, :deploys, :sshs,
91
97
  :namespace, :env, :envs, :region
92
98
  end
93
99
 
@@ -5,8 +5,9 @@ class Aerosol::AutoScaling
5
5
  logger_prefix '[aerosol auto_scaling]'
6
6
  aws_attribute :auto_scaling_group_name, :availability_zones, :min_size, :max_size, :default_cooldown,
7
7
  :desired_capacity, :health_check_grace_period, :health_check_type, :load_balancer_names,
8
- :placement_group, :tags, :created_time, :vpc_zone_identifier
8
+ :placement_group, :tags, :created_time, :vpc_zone_identifier, :target_group_arns
9
9
  aws_class_attribute :launch_configuration, Aerosol::LaunchConfiguration
10
+ aws_class_attribute :launch_template, Aerosol::LaunchTemplate
10
11
  primary_key :auto_scaling_group_name
11
12
 
12
13
  def initialize(options={}, &block)
@@ -38,21 +39,30 @@ class Aerosol::AutoScaling
38
39
  end
39
40
 
40
41
  def create!
41
- ensure_present! :launch_configuration, :max_size, :min_size
42
+ ensure_present! :max_size, :min_size
42
43
  raise 'availability_zones or vpc_zone_identifier must be set' if [availability_zones, vpc_zone_identifier].none?
44
+ raise 'launch_configuration or launch_template must be set' if [launch_configuration, launch_template].none?
43
45
 
44
46
  info "creating auto scaling group"
45
- launch_configuration.create
47
+ launch_details = create_launch_details
48
+
46
49
  info self.inspect
47
50
 
48
51
  conn.create_auto_scaling_group({
49
52
  auto_scaling_group_name: auto_scaling_group_name,
50
53
  availability_zones: [*availability_zones],
51
- launch_configuration_name: launch_configuration.launch_configuration_name,
52
54
  max_size: max_size,
53
55
  min_size: min_size
54
- }.merge(create_options))
55
- sleep 10
56
+ }
57
+ .merge(create_options)
58
+ .merge(launch_details)
59
+ )
60
+
61
+ conn.wait_until(:group_in_service, auto_scaling_group_names: [auto_scaling_group_name]) do |waiter|
62
+ waiter.before_wait do |attempt_count, _response|
63
+ info "Wait count #{attempt_count} of #{waiter.max_attempts} for #{auto_scaling_group_name} to be in service"
64
+ end
65
+ end
56
66
  end
57
67
 
58
68
  def destroy!
@@ -138,6 +148,7 @@ class Aerosol::AutoScaling
138
148
  "placement_group" => "#{placement_group}", \
139
149
  "tags" => #{tags.to_s}, \
140
150
  "created_time" => "#{created_time}" \
151
+ "target_group_arns" => "#{target_group_arns}" \
141
152
  }}
142
153
  end
143
154
 
@@ -146,6 +157,22 @@ private
146
157
  Aerosol::AWS.auto_scaling
147
158
  end
148
159
 
160
+ def create_launch_details
161
+ if launch_configuration
162
+ launch_configuration.create
163
+ { launch_configuration_name: launch_configuration.launch_configuration_name }
164
+ elsif launch_template
165
+ launch_template.create
166
+ {
167
+ launch_template:
168
+ {
169
+ launch_template_name: launch_template.launch_template_name,
170
+ version: '$Latest'
171
+ }
172
+ }
173
+ end
174
+ end
175
+
149
176
  def create_options
150
177
  {
151
178
  default_cooldown: default_cooldown,
@@ -155,7 +182,8 @@ private
155
182
  load_balancer_names: load_balancer_names,
156
183
  placement_group: placement_group,
157
184
  tags: tags_to_array,
158
- vpc_zone_identifier: vpc_zone_identifier
185
+ vpc_zone_identifier: vpc_zone_identifier,
186
+ target_group_arns: target_group_arns
159
187
  }.reject { |k, v| v.nil? }
160
188
  end
161
189
 
data/lib/aerosol/cli.rb CHANGED
@@ -14,6 +14,20 @@ class Aerosol::AbstractCommand < Clamp::Command
14
14
  end
15
15
  end
16
16
 
17
+ class Aerosol::DeployCommand < Aerosol::AbstractCommand
18
+ parameter 'DEPLOY', 'the deploy to run (can also be an environment name) for', :attribute_name => :deploy_name
19
+
20
+ def execute
21
+ super
22
+
23
+ if Aerosol.deploy(deploy_name.to_sym)
24
+ Rake::Task["aerosol:#{deploy_name}:all"].invoke
25
+ elsif Aerosol.env(deploy_name.to_sym)
26
+ Rake::Task["aerosol:env:#{deploy_name}"].invoke
27
+ end
28
+ end
29
+ end
30
+
17
31
  class Aerosol::SshCommand < Aerosol::AbstractCommand
18
32
  option ['-r', '--run'], :flag, 'run first ssh command', :attribute_name => :run_first
19
33
  parameter 'DEPLOY', 'the deploy to list commands for', :attribute_name => :deploy_name
@@ -37,5 +51,6 @@ end
37
51
 
38
52
  class Aerosol::Cli < Aerosol::AbstractCommand
39
53
  subcommand ['ssh', 's'], 'Print ssh commands for latest running instances', Aerosol::SshCommand
54
+ subcommand ['deploy', 'd'], 'Run a deploy', Aerosol::DeployCommand
40
55
  end
41
56
 
@@ -5,7 +5,7 @@ class Aerosol::LaunchConfiguration
5
5
  logger_prefix '[aerosol launch_configuration]'
6
6
  aws_attribute :launch_configuration_name, :image_id, :instance_type, :security_groups, :user_data,
7
7
  :iam_instance_profile, :kernel_id, :key_name, :spot_price, :created_time,
8
- :associate_public_ip_address, :block_device_mappings
8
+ :associate_public_ip_address, :block_device_mappings, :ebs_optimized
9
9
  dsl_attribute :meta_data
10
10
 
11
11
  primary_key :launch_configuration_name
@@ -89,7 +89,8 @@ class Aerosol::LaunchConfiguration
89
89
  "key_name" => "#{key_name}", \
90
90
  "spot_price" => "#{spot_price}", \
91
91
  "created_time" => "#{created_time}", \
92
- "block_device_mappings" => #{block_device_mappings}" \
92
+ "block_device_mappings" => #{block_device_mappings}", \
93
+ "ebs_optimized" => #{ebs_optimized} \
93
94
  }}
94
95
  end
95
96
 
@@ -109,7 +110,8 @@ private
109
110
  spot_price: spot_price,
110
111
  user_data: corrected_user_data,
111
112
  associate_public_ip_address: associate_public_ip_address,
112
- block_device_mappings: block_device_mappings
113
+ block_device_mappings: block_device_mappings,
114
+ ebs_optimized: ebs_optimized
113
115
  }.reject { |k, v| v.nil? }
114
116
  end
115
117
 
@@ -0,0 +1,133 @@
1
+ class Aerosol::LaunchTemplate
2
+ include Aerosol::AWSModel
3
+ include Dockly::Util::Logger::Mixin
4
+
5
+ logger_prefix '[aerosol launch_template]'
6
+ aws_attribute :launch_template_name, :image_id, :instance_type, :security_groups, :user_data,
7
+ :iam_instance_profile, :kernel_id, :key_name, :spot_price, :created_time,
8
+ :network_interfaces, :block_device_mappings, :ebs_optimized
9
+ dsl_attribute :meta_data
10
+
11
+ primary_key :launch_template_name
12
+ default_value(:security_groups) { [] }
13
+ default_value(:meta_data) { {} }
14
+
15
+ def launch_template_name(arg = nil)
16
+ if arg
17
+ raise "You cannot set the launch_template_name directly" unless from_aws
18
+ @launch_template_name = arg
19
+ else
20
+ @launch_template_name || default_identifier
21
+ end
22
+ end
23
+
24
+ def exists?
25
+ info "launch_template: needed?: #{launch_template_name}: " +
26
+ "checking for launch template: #{launch_template_name}"
27
+ exists = super
28
+ info "launch template: needed?: #{launch_template_name}: " +
29
+ "#{exists ? 'found' : 'did not find'} launch template: #{launch_template_name}"
30
+ exists
31
+ end
32
+
33
+ def security_group(group)
34
+ security_groups << group
35
+ end
36
+
37
+ def create!
38
+ ensure_present! :image_id, :instance_type
39
+
40
+ info "creating launch template"
41
+ conn.create_launch_template(
42
+ launch_template_name: launch_template_name,
43
+ launch_template_data: {
44
+ image_id: image_id,
45
+ instance_type: instance_type,
46
+ monitoring: {
47
+ enabled: true
48
+ },
49
+ }.merge(create_options)
50
+ )
51
+ info self.inspect
52
+ end
53
+
54
+ def destroy!
55
+ info self.to_s
56
+ raise StandardError.new('No launch_template_name found') unless launch_template_name
57
+ conn.delete_launch_template(launch_template_name: launch_template_name)
58
+ end
59
+
60
+ def all_instances
61
+ Aerosol::Instance.all.select { |instance|
62
+ !instance.launch_template.nil? &&
63
+ (instance.launch_template.launch_template == launch_template_name)
64
+ }.each(&:description)
65
+ end
66
+
67
+ def self.request_all_for_token(next_token)
68
+ options = next_token.nil? ? {} : { next_token: next_token }
69
+ Aerosol::AWS.compute.describe_launch_templates(options)
70
+ end
71
+
72
+ def self.request_all
73
+ next_token = nil
74
+ lts = []
75
+
76
+ begin
77
+ new_lts = request_all_for_token(next_token)
78
+ lts.concat(new_lts.launch_templates)
79
+ next_token = new_lts.next_token
80
+ end until next_token.nil?
81
+
82
+ lts
83
+ end
84
+
85
+ def to_s
86
+ %{Aerosol::LaunchTemplate { \
87
+ "launch_template_name" => "#{launch_template_name}", \
88
+ "image_id" => "#{image_id}", \
89
+ "instance_type" => "#{instance_type}", \
90
+ "security_group_ids" => #{security_groups.to_s}, \
91
+ "user_data" => "#{user_data}", \
92
+ "iam_instance_profile" => "#{iam_instance_profile}", \
93
+ "kernel_id" => "#{kernel_id}", \
94
+ "key_name" => "#{key_name}", \
95
+ "spot_price" => "#{spot_price}", \
96
+ "created_time" => "#{created_time}", \
97
+ "block_device_mappings" => #{block_device_mappings}", \
98
+ "ebs_optimized" => #{ebs_optimized} \
99
+ }}
100
+ end
101
+
102
+ def corrected_user_data
103
+ realized_user_data = user_data.is_a?(Proc) ? user_data.call : user_data
104
+
105
+ Base64.encode64(Aerosol::Util.strip_heredoc(realized_user_data || ''))
106
+ end
107
+
108
+ private
109
+ def create_options
110
+ instance_market_options = {
111
+ market_type: 'spot',
112
+ spot_options: {
113
+ max_price: spot_price
114
+ }
115
+ } if spot_price
116
+
117
+ {
118
+ iam_instance_profile: { name: iam_instance_profile },
119
+ kernel_id: kernel_id,
120
+ key_name: key_name,
121
+ security_group_ids: security_groups,
122
+ instance_market_options: instance_market_options,
123
+ user_data: corrected_user_data,
124
+ network_interfaces: network_interfaces,
125
+ block_device_mappings: block_device_mappings,
126
+ ebs_optimized: ebs_optimized,
127
+ }.reject { |k, v| v.nil? }
128
+ end
129
+
130
+ def conn
131
+ Aerosol::AWS.compute
132
+ end
133
+ end
@@ -1,8 +1,6 @@
1
1
  require 'rake'
2
2
  require 'aerosol'
3
3
 
4
- $rake_task_logger = Dockly::Util::Logger.new('[aerosol rake_task]', STDOUT, false)
5
-
6
4
  class Rake::AutoScalingTask < Rake::Task
7
5
  def needed?
8
6
  !auto_scaling.exists?
@@ -1,5 +1,5 @@
1
1
  # Copyright Swipely, Inc. All rights reserved.
2
2
 
3
3
  module Aerosol
4
- VERSION = '1.6.0'
4
+ VERSION = '1.9.0'
5
5
  end
@@ -0,0 +1,402 @@
1
+ require 'spec_helper'
2
+
3
+ describe Aerosol::LaunchTemplate do
4
+ subject do
5
+ described_class.new do
6
+ name :my_launch_template
7
+ image_id 'ami-123'
8
+ instance_type 'super-cool-instance-type'
9
+ user_data <<-END_OF_STRING
10
+ #!/bin/bash
11
+ rm -rf /
12
+ END_OF_STRING
13
+ end
14
+ end
15
+ before { subject.stub(:sleep) }
16
+
17
+ describe "#launch_template_name" do
18
+ context "with no namespace set" do
19
+ let(:identifier) { "my_launch_template-#{Aerosol::Util.git_sha}" }
20
+ it "returns a normal identifier" do
21
+ expect(subject.launch_template_name).to eq(identifier)
22
+ end
23
+ end
24
+
25
+ context "with a namespace set" do
26
+ let(:namespace) { "test" }
27
+ let(:identifier) { "#{namespace}-my_launch_template-#{Aerosol::Util.git_sha}" }
28
+
29
+ before { Aerosol.namespace namespace }
30
+ after { Aerosol.instance_variable_set(:"@namespace", nil) }
31
+
32
+ it "returns a namespaced identifier" do
33
+ expect(subject.launch_template_name).to eq(identifier)
34
+ end
35
+ end
36
+ end
37
+
38
+ describe '#security_group' do
39
+ subject { described_class.new!(:name => 'conf-conf-conf') }
40
+
41
+ it 'adds the argument to the list of security groups' do
42
+ expect { subject.security_group 'my group' }
43
+ .to change { subject.security_groups.length }
44
+ .by 1
45
+ end
46
+
47
+ it 'does not the default security group' do
48
+ expect { subject.security_group 'other test' }
49
+ .to_not change { described_class.default_values[:security_groups] }
50
+ end
51
+ end
52
+
53
+ describe '#create!' do
54
+ context 'when some required fields are nil' do
55
+ before { subject.instance_variable_set(:@image_id, nil) }
56
+
57
+ it 'raises an error' do
58
+ expect { subject.create! }.to raise_error
59
+ end
60
+ end
61
+
62
+ context 'when everything is present' do
63
+ context 'and the launch template already exists' do
64
+ it 'raises an error' do
65
+ Aerosol::AWS.compute.stub_responses(
66
+ :create_launch_template,
67
+ Aws::EC2::Errors::AlreadyExists
68
+ )
69
+ expect { subject.create! }.to raise_error
70
+ end
71
+ end
72
+
73
+ context 'and the launch template does not exist yet' do
74
+ after { subject.destroy! rescue nil }
75
+
76
+ it 'creates the launch template group' do
77
+ Aerosol::AWS.compute.stub_responses(:create_launch_template, [])
78
+ expect { subject.create! }.to_not raise_error
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ describe '#destroy!' do
85
+ context 'when the launch_template_name is nil' do
86
+
87
+ it 'raises an error' do
88
+ allow(subject).to receive(:launch_template_name).and_return(nil)
89
+ Aerosol::AWS.compute.stub_responses(:delete_launch_template, [])
90
+ expect { subject.destroy! }.to raise_error
91
+ end
92
+ end
93
+
94
+ context 'when the launch_template_name is present' do
95
+ context 'but the launch template does not exist' do
96
+ it 'raises an error' do
97
+ Aerosol::AWS.compute.stub_responses(
98
+ :delete_launch_template,
99
+ Aws::EC2::Errors::ValidationError
100
+ )
101
+ expect { subject.destroy! }.to raise_error
102
+ end
103
+ end
104
+
105
+ context 'and the launch template exists' do
106
+ it 'deletes the launch template' do
107
+ Aerosol::AWS.compute.stub_responses(:delete_launch_template, [])
108
+ expect { subject.destroy! }.to_not raise_error
109
+ end
110
+ end
111
+ end
112
+ end
113
+
114
+ describe '#create' do
115
+ context 'when the launch_template_name is nil' do
116
+ subject do
117
+ described_class.new! do
118
+ name :random_test_name
119
+ image_id 'test-ami-who-even-cares-really'
120
+ instance_type 'm1.large'
121
+ end
122
+ end
123
+
124
+ it 'raises an error' do
125
+ allow(subject).to receive(:launch_template_name).and_return(nil)
126
+ Aerosol::AWS.compute.stub_responses(:create_launch_template, [])
127
+ Aerosol::AWS.compute.stub_responses(:describe_launch_templates, {
128
+ launch_templates: [], next_token: nil
129
+ })
130
+ expect { subject.create }.to raise_error
131
+ end
132
+ end
133
+
134
+ context 'when the launch_template_name is present' do
135
+ subject do
136
+ described_class.new! do
137
+ name :random_test_name_2
138
+ image_id 'test-ami-who-even-cares-really'
139
+ instance_type 'm1.large'
140
+ end
141
+ end
142
+
143
+ context 'but the launch template already exists' do
144
+ it 'does not call #create!' do
145
+ Aerosol::AWS.compute.stub_responses(:describe_launch_templates, {
146
+ launch_templates: [{
147
+ launch_template_name: subject.launch_template_name,
148
+ }],
149
+ next_token: nil
150
+ })
151
+ expect(subject).to_not receive(:create!)
152
+ subject.create
153
+ end
154
+ end
155
+
156
+ context 'and the launch template does not yet exist' do
157
+ it 'creates it' do
158
+ Aerosol::AWS.compute.stub_responses(:describe_launch_templates, {
159
+ launch_templates: [],
160
+ next_token: nil
161
+ })
162
+ subject.should_receive(:create!)
163
+ subject.create
164
+ end
165
+ end
166
+ end
167
+ end
168
+
169
+ describe '#destroy' do
170
+ subject do
171
+ described_class.new! do
172
+ name :random_test_name_3
173
+ image_id 'awesome-ami'
174
+ instance_type 'm1.large'
175
+ end
176
+ end
177
+
178
+ context 'when the launch_template_name is nil' do
179
+ it 'raises an error' do
180
+ allow(subject).to receive(:launch_template_name).and_return(nil)
181
+ Aerosol::AWS.compute.stub_responses(:describe_launch_templates, {
182
+ launch_templates: [],
183
+ next_token: nil
184
+ })
185
+ expect { subject.create }.to raise_error(ArgumentError)
186
+ end
187
+ end
188
+
189
+ context 'when the launch_template_name is present' do
190
+ context 'and the launch template already exists' do
191
+
192
+ it 'calls #destroy!' do
193
+ Aerosol::AWS.compute.stub_responses(:describe_launch_templates, {
194
+ launch_templates: [{
195
+ launch_template_name: subject.launch_template_name
196
+ }],
197
+ next_token: nil
198
+ })
199
+ subject.should_receive(:destroy!)
200
+ subject.destroy
201
+ end
202
+ end
203
+
204
+ context 'but the launch template does not yet exist' do
205
+ it 'does not call #destroy!' do
206
+ Aerosol::AWS.compute.stub_responses(:describe_launch_templates, {
207
+ launch_templates: [],
208
+ next_token: nil
209
+ })
210
+ subject.should_not_receive(:destroy!)
211
+ subject.destroy
212
+ end
213
+ end
214
+ end
215
+ end
216
+
217
+ describe '.exists?' do
218
+ subject { described_class }
219
+ let(:instance) do
220
+ subject.new! do
221
+ name :exists_test_name
222
+ image_id 'ami123'
223
+ instance_type 'm1.large'
224
+ stub(:sleep)
225
+ end
226
+ end
227
+
228
+ context 'when the argument exists' do
229
+ it 'returns true' do
230
+ Aerosol::AWS.compute.stub_responses(:describe_launch_templates, {
231
+ launch_templates: [{
232
+ launch_template_name: instance.launch_template_name,
233
+ }],
234
+ next_token: nil
235
+ })
236
+ subject.exists?(instance.launch_template_name).should be_true
237
+ end
238
+ end
239
+
240
+ context 'when the argument does not exist' do
241
+ let(:instance) { described_class.new! }
242
+
243
+ it 'returns false' do
244
+ Aerosol::AWS.compute.stub_responses(:describe_launch_templates, {
245
+ launch_templates: [],
246
+ next_token: nil
247
+ })
248
+ subject.exists?(instance.launch_template_name).should be_false
249
+ end
250
+ end
251
+ end
252
+
253
+ describe '.request_all' do
254
+ describe 'repeats until no NextToken' do
255
+ it 'should include both autoscaling groups lists' do
256
+ Aerosol::AWS.compute.stub_responses(:describe_launch_templates, [
257
+ {
258
+ launch_templates: [
259
+ { launch_template_name: '1' },
260
+ { launch_template_name: '4' }
261
+ ],
262
+ next_token: 'yes'
263
+ },
264
+ {
265
+ launch_templates: [
266
+ { launch_template_name: '2' },
267
+ { launch_template_name: '3' }
268
+ ],
269
+ next_token: nil
270
+ }
271
+ ])
272
+ expect(Aerosol::LaunchTemplate.request_all.map(&:launch_template_name)).to eq(['1','4','2','3'])
273
+ end
274
+ end
275
+ end
276
+
277
+ describe '.all' do
278
+ subject { described_class }
279
+
280
+ context 'when there are no launch templates' do
281
+ before do
282
+ Aerosol::AWS.compute.stub_responses(:describe_launch_templates, [
283
+ { launch_templates: [], next_token: nil }
284
+ ])
285
+ end
286
+ its(:all) { should be_empty }
287
+ end
288
+
289
+ context 'when there are launch templates' do
290
+ let(:insts) {
291
+ [
292
+ { launch_template_name: 'test' },
293
+ { launch_template_name: 'test2' }
294
+ ]
295
+ }
296
+
297
+ it 'returns each of them' do
298
+ Aerosol::AWS.compute.stub_responses(:describe_launch_templates, {
299
+ launch_templates: insts,
300
+ next_token: nil
301
+ })
302
+ subject.all.map(&:launch_template_name).should == %w[test test2]
303
+ end
304
+ end
305
+ end
306
+
307
+ describe '.from_hash' do
308
+ context 'when the launch template has not been initialized' do
309
+ subject { described_class.from_hash(hash) }
310
+ let(:hash) do
311
+ {
312
+ launch_template_name: '~test-launch-config~',
313
+ image_id: 'ami-123',
314
+ instance_type: 'm1.large',
315
+ security_groups: [],
316
+ user_data: 'echo hi',
317
+ iam_instance_profile: nil,
318
+ kernel_id: 'kernel-id',
319
+ key_name: 'key-name',
320
+ spot_price: '0.04',
321
+ }
322
+ end
323
+
324
+ it 'creates a new launch template with the specified values' do
325
+ subject.launch_template_name.should == '~test-launch-config~'
326
+ subject.image_id.should == 'ami-123'
327
+ subject.instance_type.should == 'm1.large'
328
+ subject.security_groups.should be_empty
329
+ subject.user_data.should == 'echo hi'
330
+ subject.iam_instance_profile.should be_nil
331
+ subject.kernel_id.should == 'kernel-id'
332
+ subject.spot_price.should == '0.04'
333
+ subject.from_aws = true
334
+ end
335
+
336
+ it 'generates a name' do
337
+ subject.name.to_s.should start_with 'LaunchTemplate_'
338
+ end
339
+ end
340
+
341
+ context 'when the launch template has already been initialized' do
342
+ let(:old_hash) do
343
+ {
344
+ launch_template_name: 'this-aws-id-abc-123',
345
+ image_id: 'ami-456',
346
+ }
347
+ end
348
+ let(:new_hash) { old_hash.merge(instance_type: 'm1.large') }
349
+ let!(:existing) { described_class.from_hash(old_hash) }
350
+ let(:new) { described_class.from_hash(new_hash) }
351
+
352
+ it 'makes a new instance' do
353
+ expect { new }.to change { described_class.instances.length }.by(1)
354
+ new.launch_template_name.should == 'this-aws-id-abc-123'
355
+ new.image_id.should == 'ami-456'
356
+ end
357
+ end
358
+ end
359
+
360
+ describe '#corrected_user_data' do
361
+ let(:encoded_user_data_string) { Base64.encode64('test') }
362
+
363
+ context 'when the user_data is a String' do
364
+ subject do
365
+ described_class.new do
366
+ name :corrected_user_data
367
+ user_data 'test'
368
+ end
369
+ end
370
+
371
+ it 'correctly encodes to base64' do
372
+ expect(subject.corrected_user_data).to eq(encoded_user_data_string)
373
+ end
374
+ end
375
+
376
+ context 'when the user_data is a Proc' do
377
+ subject do
378
+ described_class.new do
379
+ name :corrected_user_data_2
380
+ user_data { 'test' }
381
+ end
382
+ end
383
+
384
+ it 'correctly encodes to base64' do
385
+ expect(subject.corrected_user_data).to eq(encoded_user_data_string)
386
+ end
387
+ end
388
+ end
389
+
390
+ describe '#meta_data' do
391
+ subject do
392
+ described_class.new do
393
+ name :my_launch_template
394
+ meta_data('Test' => '1')
395
+ end
396
+ end
397
+
398
+ it 'returns the hash' do
399
+ expect(subject.meta_data['Test']).to eq('1')
400
+ end
401
+ end
402
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aerosol
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 1.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Swipely, Inc.
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-24 00:00:00.000000000 Z
11
+ date: 2021-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -53,19 +53,61 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: aws-sdk
56
+ name: aws-sdk-core
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '2.0'
61
+ version: '3'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '2.0'
68
+ version: '3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: aws-sdk-s3
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1'
83
+ - !ruby/object:Gem::Dependency
84
+ name: aws-sdk-ec2
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1'
97
+ - !ruby/object:Gem::Dependency
98
+ name: aws-sdk-autoscaling
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1'
69
111
  - !ruby/object:Gem::Dependency
70
112
  name: minigit
71
113
  requirement: !ruby/object:Gem::Requirement
@@ -154,16 +196,16 @@ dependencies:
154
196
  name: rake
155
197
  requirement: !ruby/object:Gem::Requirement
156
198
  requirements:
157
- - - ">="
199
+ - - "~>"
158
200
  - !ruby/object:Gem::Version
159
- version: '0'
201
+ version: '10.0'
160
202
  type: :development
161
203
  prerelease: false
162
204
  version_requirements: !ruby/object:Gem::Requirement
163
205
  requirements:
164
- - - ">="
206
+ - - "~>"
165
207
  - !ruby/object:Gem::Version
166
- version: '0'
208
+ version: '10.0'
167
209
  - !ruby/object:Gem::Dependency
168
210
  name: rspec
169
211
  requirement: !ruby/object:Gem::Requirement
@@ -238,6 +280,7 @@ files:
238
280
  - lib/aerosol/env.rb
239
281
  - lib/aerosol/instance.rb
240
282
  - lib/aerosol/launch_configuration.rb
283
+ - lib/aerosol/launch_template.rb
241
284
  - lib/aerosol/rake_task.rb
242
285
  - lib/aerosol/runner.rb
243
286
  - lib/aerosol/util.rb
@@ -250,6 +293,7 @@ files:
250
293
  - spec/aerosol/env_spec.rb
251
294
  - spec/aerosol/instance_spec.rb
252
295
  - spec/aerosol/launch_configuration_spec.rb
296
+ - spec/aerosol/launch_template_spec.rb
253
297
  - spec/aerosol/rake_task_spec.rb
254
298
  - spec/aerosol/runner_spec.rb
255
299
  - spec/aerosol_spec.rb
@@ -259,7 +303,7 @@ homepage: https://github.com/swipely/aerosol
259
303
  licenses:
260
304
  - MIT
261
305
  metadata: {}
262
- post_install_message:
306
+ post_install_message:
263
307
  rdoc_options: []
264
308
  require_paths:
265
309
  - lib
@@ -274,9 +318,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
274
318
  - !ruby/object:Gem::Version
275
319
  version: '0'
276
320
  requirements: []
277
- rubyforge_project:
278
- rubygems_version: 2.4.5
279
- signing_key:
321
+ rubygems_version: 3.0.3
322
+ signing_key:
280
323
  specification_version: 4
281
324
  summary: Instance-based deploys made easy
282
325
  test_files:
@@ -288,9 +331,9 @@ test_files:
288
331
  - spec/aerosol/env_spec.rb
289
332
  - spec/aerosol/instance_spec.rb
290
333
  - spec/aerosol/launch_configuration_spec.rb
334
+ - spec/aerosol/launch_template_spec.rb
291
335
  - spec/aerosol/rake_task_spec.rb
292
336
  - spec/aerosol/runner_spec.rb
293
337
  - spec/aerosol_spec.rb
294
338
  - spec/spec_helper.rb
295
339
  - spec/support/vcr.rb
296
- has_rdoc: