tass 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/tass +97 -0
- data/lib/tapjoy/autoscaling_bootstrap/AWS/Autoscaling/group.rb +61 -0
- data/lib/tapjoy/autoscaling_bootstrap/AWS/Autoscaling/launch_config.rb +45 -0
- data/lib/tapjoy/autoscaling_bootstrap/AWS/autoscaling.rb +45 -0
- data/lib/tapjoy/autoscaling_bootstrap/AWS/cloudwatch.rb +41 -0
- data/lib/tapjoy/autoscaling_bootstrap/AWS/ec2.rb +23 -0
- data/lib/tapjoy/autoscaling_bootstrap/AWS/elb.rb +55 -0
- data/lib/tapjoy/autoscaling_bootstrap/alerts/monitoring.rb +38 -0
- data/lib/tapjoy/autoscaling_bootstrap/alerts/scaling.rb +75 -0
- data/lib/tapjoy/autoscaling_bootstrap/alerts.rb +7 -0
- data/lib/tapjoy/autoscaling_bootstrap/audit.rb +49 -0
- data/lib/tapjoy/autoscaling_bootstrap/autoscaling/config.rb +38 -0
- data/lib/tapjoy/autoscaling_bootstrap/autoscaling/group.rb +113 -0
- data/lib/tapjoy/autoscaling_bootstrap/autoscaling/policy.rb +37 -0
- data/lib/tapjoy/autoscaling_bootstrap/autoscaling.rb +6 -0
- data/lib/tapjoy/autoscaling_bootstrap/autoscaling_group.rb +59 -0
- data/lib/tapjoy/autoscaling_bootstrap/aws.rb +7 -0
- data/lib/tapjoy/autoscaling_bootstrap/cloudwatch.rb +29 -0
- data/lib/tapjoy/autoscaling_bootstrap/configure_autoscaler.rb +40 -0
- data/lib/tapjoy/autoscaling_bootstrap/elb.rb +56 -0
- data/lib/tapjoy/autoscaling_bootstrap/errors/elb.rb +48 -0
- data/lib/tapjoy/autoscaling_bootstrap/errors.rb +30 -0
- data/lib/tapjoy/autoscaling_bootstrap/launch_configuration.rb +42 -0
- data/lib/tapjoy/autoscaling_bootstrap/version.rb +11 -0
- data/lib/tapjoy/autoscaling_bootstrap.rb +165 -0
- metadata +182 -0
@@ -0,0 +1,113 @@
|
|
1
|
+
module Tapjoy
|
2
|
+
module AutoscalingBootstrap
|
3
|
+
module Autoscaling
|
4
|
+
# Class for Autoscaling groups
|
5
|
+
class Group
|
6
|
+
|
7
|
+
# Initialize the class
|
8
|
+
def initialize
|
9
|
+
@scaler_name = Tapjoy::AutoscalingBootstrap.scaler_name
|
10
|
+
@config_name = Tapjoy::AutoscalingBootstrap.config_name
|
11
|
+
@elb_name = Tapjoy::AutoscalingBootstrap.elb_name
|
12
|
+
@create_elb = Tapjoy::AutoscalingBootstrap.create_elb
|
13
|
+
end
|
14
|
+
|
15
|
+
# Create autoscaling group
|
16
|
+
def create(config:, aws_env:, user_data:)
|
17
|
+
if exists
|
18
|
+
begin
|
19
|
+
zero_autoscale_group
|
20
|
+
rescue Aws::AutoScaling::Errors::ValidationError => err
|
21
|
+
abort("Cannot remove existing AS group #{@scaler_name}. Error: #{err}")
|
22
|
+
end
|
23
|
+
else
|
24
|
+
"Scaling group #{@scaler_name} does not exist, continuing..."
|
25
|
+
end
|
26
|
+
|
27
|
+
Tapjoy::AutoscalingBootstrap.config.create(config, aws_env,
|
28
|
+
user_data)
|
29
|
+
|
30
|
+
puts "Creating scaling group: #{@scaler_name}"
|
31
|
+
Tapjoy::AutoscalingBootstrap::AWS::Autoscaling::Group.create(**config)
|
32
|
+
create_termination_notification(config)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Check if autoscale group exists
|
36
|
+
def exists
|
37
|
+
!Tapjoy::AutoscalingBootstrap::AWS::Autoscaling::Group.describe.nil?
|
38
|
+
end
|
39
|
+
|
40
|
+
# Encode user data into required base64 form
|
41
|
+
def encode_user_data(user_data)
|
42
|
+
Base64.encode64("#{user_data}")
|
43
|
+
end
|
44
|
+
|
45
|
+
# Create tags array to pass to autoscaling group
|
46
|
+
def generate_tags(tags)
|
47
|
+
tag_array = Array.new
|
48
|
+
return [] if tags.nil? || tags.empty?
|
49
|
+
tags.each do |t|
|
50
|
+
return [] if t.nil?
|
51
|
+
t.each_pair do |key, value|
|
52
|
+
tag_array << {
|
53
|
+
resource_id: @scaler_name,
|
54
|
+
resource_type: 'auto-scaling-group',
|
55
|
+
key: key.to_s,
|
56
|
+
value: value,
|
57
|
+
propagate_at_launch: true,
|
58
|
+
}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
tag_array
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
# Clear out existing autoscaling group
|
67
|
+
def zero_autoscale_group
|
68
|
+
Tapjoy::AutoscalingBootstrap::AWS::Autoscaling::Group.resize
|
69
|
+
|
70
|
+
wait_for_asg_to_quiet
|
71
|
+
|
72
|
+
Tapjoy::AutoscalingBootstrap::AWS::Autoscaling::Group.delete
|
73
|
+
|
74
|
+
wait_for_asg_to_delete
|
75
|
+
|
76
|
+
abort("#{@scaler_name} still exists") if exists
|
77
|
+
end
|
78
|
+
|
79
|
+
# Create termination notification for Chef
|
80
|
+
def create_termination_notification(misc_config)
|
81
|
+
puts 'Create termination notification'
|
82
|
+
begin
|
83
|
+
Tapjoy::AutoscalingBootstrap::AWS::Autoscaling.put_notification_configuration(
|
84
|
+
**misc_config)
|
85
|
+
rescue Aws::AutoScaling::Errors::ValidationError => err
|
86
|
+
STDERR.puts "Cannot create notification: #{err}"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Wait for ASG activities to settle before proceeding
|
91
|
+
def wait_for_asg_to_quiet
|
92
|
+
5.times do |tries|
|
93
|
+
puts "Waiting for scaling activities to settle (#{tries + 1} of 5)..."
|
94
|
+
as_group_size=Tapjoy::AutoscalingBootstrap::AWS::Autoscaling::Group.describe[:instances].length
|
95
|
+
|
96
|
+
break if as_group_size.eql?(0)
|
97
|
+
|
98
|
+
Tapjoy::AutoscalingBootstrap::Base.new.aws_wait(tries)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Wait for ASG to be deleted
|
103
|
+
def wait_for_asg_to_delete
|
104
|
+
5.times do |tries|
|
105
|
+
puts "Waiting for auto scaling group to remove itself (#{tries + 1} of 5)..."
|
106
|
+
break unless exists
|
107
|
+
Tapjoy::AutoscalingBootstrap::Base.new.aws_wait(tries)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Tapjoy
|
2
|
+
module AutoscalingBootstrap
|
3
|
+
module Autoscaling
|
4
|
+
# Class for Autoscaling policies
|
5
|
+
class Policy
|
6
|
+
|
7
|
+
# Initialize the class
|
8
|
+
def initialize
|
9
|
+
@scaler_name = Tapjoy::AutoscalingBootstrap.scaler_name
|
10
|
+
@group = Tapjoy::AutoscalingBootstrap.group
|
11
|
+
end
|
12
|
+
|
13
|
+
# Create autoscaling policy
|
14
|
+
def create(policy, scale)
|
15
|
+
return unless Tapjoy::AutoscalingBootstrap.group.exists
|
16
|
+
Tapjoy::AutoscalingBootstrap::AWS::Autoscaling.put_scaling_policy(
|
17
|
+
policy_name: policy, **scale)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Delete scaling policies
|
21
|
+
def delete(policy)
|
22
|
+
return unless @group.exists
|
23
|
+
|
24
|
+
if Tapjoy::AutoscalingBootstrap::AWS::Autoscaling.describe_policies(
|
25
|
+
policy: policy)[0].length > 0
|
26
|
+
|
27
|
+
puts "Deleting policy: #{policy}"
|
28
|
+
Tapjoy::AutoscalingBootstrap::AWS::Autoscaling.delete_policy(
|
29
|
+
policy: policy)
|
30
|
+
else
|
31
|
+
STDERR.puts "'#{policy}' doesn't exist. Skipping..."
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Tapjoy
|
2
|
+
module AutoscalingBootstrap
|
3
|
+
# This class is the central launching point for new autoscaling group creation
|
4
|
+
class AutoscalingGroup
|
5
|
+
# Initialize the class
|
6
|
+
def create(opts, new_config, aws_env, user_data,
|
7
|
+
|
8
|
+
# ELB Parameters
|
9
|
+
elb_health_target: "#{new_config[:instance_protocol]}:#{new_config[:instance_port]}/healthz",
|
10
|
+
elb_protocol: new_config[:instance_protocol],
|
11
|
+
elb_name: "#{new_config[:name].gsub('_','-')}-discovery"
|
12
|
+
)
|
13
|
+
|
14
|
+
if new_config[:create_elb]
|
15
|
+
new_config.merge!({
|
16
|
+
elb_health_target: elb_health_target,
|
17
|
+
elb_protocol: elb_protocol,
|
18
|
+
elb_name: elb_name
|
19
|
+
})
|
20
|
+
|
21
|
+
Tapjoy::AutoscalingBootstrap::ELB.new.create(new_config, aws_env)
|
22
|
+
else
|
23
|
+
puts "\nNo ELB required"
|
24
|
+
end
|
25
|
+
|
26
|
+
Tapjoy::AutoscalingBootstrap::ConfigureAutoscalers.new(**new_config,
|
27
|
+
aws_env: aws_env, user_data: user_data, misc_config: new_config)
|
28
|
+
|
29
|
+
scaler_name = Tapjoy::AutoscalingBootstrap.scaler_name
|
30
|
+
config_name = Tapjoy::AutoscalingBootstrap.config_name
|
31
|
+
|
32
|
+
if new_config[:autoscale]
|
33
|
+
new_config.merge!({
|
34
|
+
alarm_low_scale: "#{new_config[:human_name]} - Scale Down - Low CPU Utilization",
|
35
|
+
alarm_high_scale: "#{new_config[:human_name]} - Scale Up - High CPU Utilization",
|
36
|
+
policy_up: "#{new_config[:name]}-up-policy",
|
37
|
+
policy_down: "#{new_config[:name]}-down-policy"
|
38
|
+
})
|
39
|
+
Tapjoy::AutoscalingBootstrap::Alerts::Scaling.new(new_config)
|
40
|
+
end
|
41
|
+
|
42
|
+
if new_config[:alerts]
|
43
|
+
monitoring_alerts = Tapjoy::AutoscalingBootstrap::Alerts::Monitoring.new
|
44
|
+
monitoring_alert_config = {
|
45
|
+
alarm_low_alert: "#{new_config[:human_name]} - ALARM - Extremely Low CPU Utilization",
|
46
|
+
alarm_high_alert: "#{new_config[:human_name]} - ALARM - Extremely High CPU Utilization",
|
47
|
+
notification: "#{new_config[:sns_base_arn]}:General-NOC-Notifications"
|
48
|
+
}
|
49
|
+
monitoring_alerts.create(**monitoring_alert_config)
|
50
|
+
end
|
51
|
+
|
52
|
+
puts "\n\nCreated -- "
|
53
|
+
puts "Autoscaling Group: #{scaler_name}"
|
54
|
+
puts "Launch Config: #{config_name}"
|
55
|
+
puts 'Instance Count: 0'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Tapjoy
|
2
|
+
module AutoscalingBootstrap
|
3
|
+
# This module configures cloudwatch alarms
|
4
|
+
module Cloudwatch
|
5
|
+
class << self
|
6
|
+
# Create autoscaling alarms
|
7
|
+
def create_alarm(scale_alert)
|
8
|
+
puts "Creating: #{scale_alert[:alarm]}"
|
9
|
+
Tapjoy::AutoscalingBootstrap::AWS::Cloudwatch.put_metric_alarm(
|
10
|
+
**scale_alert)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Delete autoscaling alarms
|
14
|
+
def delete_alarm(alarm)
|
15
|
+
if self.alarm_exists(alarm)
|
16
|
+
puts "Deleting alarm: #{alarm}"
|
17
|
+
Tapjoy::AutoscalingBootstrap::AWS::Cloudwatch.delete_alarm(alarm)
|
18
|
+
else
|
19
|
+
STDERR.puts "'#{alarm}' doesn't exist. Skipping..."
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def alarm_exists(alarm)
|
24
|
+
Tapjoy::AutoscalingBootstrap::AWS::Cloudwatch.describe_alarm(alarm).length > 0
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Tapjoy
|
2
|
+
module AutoscalingBootstrap
|
3
|
+
# This class configures autoscaling groups
|
4
|
+
class ConfigureAutoscalers
|
5
|
+
# required arguments first, then optional
|
6
|
+
def initialize(misc_config:, aws_env:, user_data:, **unused_values)
|
7
|
+
|
8
|
+
if misc_config[:create_as_group]
|
9
|
+
sec_group_exists(aws_env[:security_groups]) unless misc_config[:vpc_subnets]
|
10
|
+
create_autoscaling_group(misc_config, aws_env, user_data)
|
11
|
+
else
|
12
|
+
puts 'Skipping creating autoscale group and launch config'
|
13
|
+
puts "\n"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
# Check if security group exists and create it if it does not
|
20
|
+
def sec_group_exists(groups)
|
21
|
+
groups.each do |group|
|
22
|
+
begin
|
23
|
+
puts "Verifying #{group} exists..."
|
24
|
+
group = Tapjoy::AutoscalingBootstrap::AWS::EC2.describe_security_groups(group)
|
25
|
+
rescue Aws::EC2::Errors::InvalidGroupNotFound => err
|
26
|
+
STDERR.puts "Warning: #{err}"
|
27
|
+
puts "Creating #{group} for #{Tapjoy::AutoscalingBootstrap.scaler_name}"
|
28
|
+
Tapjoy::AutoscalingBootstrap::AWS::EC2.create_security_group(group)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Create ASG logic
|
34
|
+
def create_autoscaling_group(misc_config, aws_env, user_data)
|
35
|
+
Tapjoy::AutoscalingBootstrap.group.create(config: misc_config,
|
36
|
+
aws_env: aws_env, user_data: user_data)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Tapjoy
|
2
|
+
module AutoscalingBootstrap
|
3
|
+
# This class configures elastic load balancers
|
4
|
+
class ELB
|
5
|
+
# Initialize the class
|
6
|
+
def initialize
|
7
|
+
end
|
8
|
+
|
9
|
+
# Create load balancer
|
10
|
+
def create(config, aws_env)
|
11
|
+
|
12
|
+
check_valid_config(config)
|
13
|
+
delete if exists
|
14
|
+
Tapjoy::AutoscalingBootstrap::AWS::ELB.create(**config, **aws_env)
|
15
|
+
health_check(config)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Configure health check
|
19
|
+
def health_check(config)
|
20
|
+
abort('Target must be specified') if config[:elb_health_target].nil?
|
21
|
+
|
22
|
+
begin
|
23
|
+
Tapjoy::AutoscalingBootstrap::AWS::ELB.health_check(**config)
|
24
|
+
rescue Aws::ElasticLoadBalancing::Errors::ValidationError => err
|
25
|
+
abort("Fatal! Invalid ELB Configuration: #{err}")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Check if ELB exists
|
30
|
+
def exists
|
31
|
+
begin
|
32
|
+
Tapjoy::AutoscalingBootstrap::AWS::ELB.describe
|
33
|
+
return true
|
34
|
+
rescue Aws::ElasticLoadBalancing::Errors::LoadBalancerNotFound => err
|
35
|
+
STDERR.puts "Warning: #{err}"
|
36
|
+
return false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Delete ELB
|
41
|
+
def delete
|
42
|
+
puts 'Removing existing ELB'
|
43
|
+
Tapjoy::AutoscalingBootstrap::AWS::ELB.delete
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
# Check configuration
|
48
|
+
def check_valid_config(config)
|
49
|
+
fail Tapjoy::AutoscalingBootstrap::Errors::ELB::NameTooLong if Tapjoy::AutoscalingBootstrap.elb_name.length > 32
|
50
|
+
fail Tapjoy::AutoscalingBootstrap::Errors::ELB::NotAnELB if Tapjoy::AutoscalingBootstrap.elb_name.eql?'NaE'
|
51
|
+
fail Tapjoy::AutoscalingBootstrap::Errors::ELB::MissingPort if config[:elb_port].nil?
|
52
|
+
fail Tapjoy::AutoscalingBootstrap::Errors::ELB::MissingInstanceProtocol if config[:instance_protocol].nil?
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Tapjoy
|
2
|
+
module AutoscalingBootstrap
|
3
|
+
module Errors
|
4
|
+
module ELB
|
5
|
+
# Raise if we try to overwrite an unclobbered ELB
|
6
|
+
class ClobberRequired < ArgumentError
|
7
|
+
def initialize
|
8
|
+
elb_name = Tapjoy::AutoscalingBootstrap.elb_name
|
9
|
+
error = 'CLOBBER_ELB env var was not true, CREATE_ELB setting was ' \
|
10
|
+
"true and ELB '#{elb_name}' exists so we are aborting."
|
11
|
+
abort(error)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Raise if ELB Name is too long
|
16
|
+
class NameTooLong < NameError
|
17
|
+
def initialize
|
18
|
+
elb_name = Tapjoy::AutoscalingBootstrap.elb_name
|
19
|
+
error = "ELB Name too long: #{elb_name.length} characters. " \
|
20
|
+
'Must be less than 32'
|
21
|
+
abort(error)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Raise if NaE
|
26
|
+
class NotAnELB < ArgumentError
|
27
|
+
def initialize
|
28
|
+
abort('CREATE_ELB specified without a name')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Raise if ELB port is missing
|
33
|
+
class MissingPort < ArgumentError
|
34
|
+
def initialize
|
35
|
+
abort('ELB port must be specified')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Raise if ELB instance protocol is missing
|
40
|
+
class MissingInstanceProtocol < ArgumentError
|
41
|
+
def initialize
|
42
|
+
abort('Instance protocol must be specified')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Tapjoy
|
2
|
+
module AutoscalingBootstrap
|
3
|
+
module Errors
|
4
|
+
# Raise if we try to overwrite an unclobbered ASG
|
5
|
+
class ClobberRequired < ArgumentError
|
6
|
+
def initialize
|
7
|
+
scaler_name = Tapjoy::AutoscalingBootstrap.scaler_name
|
8
|
+
error = 'CLOBBER env var was not true, CREATE_AS_GROUP setting ' \
|
9
|
+
"true and autoscale group '#{scaler_name}' exists so we are aborting."
|
10
|
+
abort(error)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Raise if an invalid environment is specified
|
15
|
+
class InvalidEnvironment < ArgumentError
|
16
|
+
def initialize
|
17
|
+
abort('Invalid environment specified')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Raise if an invalid launch configuration or autoscaling group
|
22
|
+
# is specified
|
23
|
+
class InvalidAutoscalingGroup < NoMethodError
|
24
|
+
def initialize
|
25
|
+
abort("ERROR: Specified autoscaling group doesn't exist")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Tapjoy
|
2
|
+
module AutoscalingBootstrap
|
3
|
+
# This class is the central launching point for autoscaling group update
|
4
|
+
class LaunchConfiguration
|
5
|
+
# Initialize the class
|
6
|
+
def initialize(new_config, aws_env, user_data)
|
7
|
+
Tapjoy::AutoscalingBootstrap.scaler_name = "#{new_config[:name]}-group"
|
8
|
+
Tapjoy::AutoscalingBootstrap.config_name = "#{new_config[:name]}-config"
|
9
|
+
|
10
|
+
updated_config = current.to_hash.merge!(new_config)
|
11
|
+
|
12
|
+
lc_name = "#{updated_config[:launch_configuration_name].split('-config')[0]}-config_#{date_stamp}"
|
13
|
+
update(config_name: lc_name, user_data: user_data,
|
14
|
+
updated_config: updated_config, aws_env: aws_env)
|
15
|
+
end
|
16
|
+
|
17
|
+
def current
|
18
|
+
begin
|
19
|
+
current_config_name = Tapjoy::AutoscalingBootstrap::AWS::Autoscaling::Group.describe[:launch_configuration_name]
|
20
|
+
rescue NoMethodError
|
21
|
+
raise Tapjoy::AutoscalingBootstrap::Errors::InvalidAutoscalingGroup
|
22
|
+
end
|
23
|
+
puts "Current launch config is: #{current_config_name}\n\n"
|
24
|
+
Tapjoy::AutoscalingBootstrap::AWS::Autoscaling::LaunchConfig.describe(current_config_name)
|
25
|
+
end
|
26
|
+
|
27
|
+
def update(config_name:, scaler_name: 'NaS', user_data: user_data,
|
28
|
+
updated_config:, aws_env:)
|
29
|
+
|
30
|
+
Tapjoy::AutoscalingBootstrap.config_name = config_name
|
31
|
+
Tapjoy::AutoscalingBootstrap.scaler_name = scaler_name
|
32
|
+
|
33
|
+
Tapjoy::AutoscalingBootstrap.config.create(updated_config, aws_env,
|
34
|
+
user_data)
|
35
|
+
end
|
36
|
+
|
37
|
+
def date_stamp
|
38
|
+
Time.now.strftime('%Y%m%d-%H%M%S')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
require 'aws-sdk-core'
|
2
|
+
require 'highline/import'
|
3
|
+
require 'base64'
|
4
|
+
require 'yaml'
|
5
|
+
require 'trollop'
|
6
|
+
require 'erb'
|
7
|
+
require 'hashdiff'
|
8
|
+
|
9
|
+
# relative requires
|
10
|
+
require_relative 'autoscaling_bootstrap/elb'
|
11
|
+
require_relative 'autoscaling_bootstrap/autoscaling'
|
12
|
+
require_relative 'autoscaling_bootstrap/autoscaling/config'
|
13
|
+
require_relative 'autoscaling_bootstrap/autoscaling/policy'
|
14
|
+
require_relative 'autoscaling_bootstrap/autoscaling/group'
|
15
|
+
require_relative 'autoscaling_bootstrap/cloudwatch'
|
16
|
+
require_relative 'autoscaling_bootstrap/configure_autoscaler'
|
17
|
+
require_relative 'autoscaling_bootstrap/errors'
|
18
|
+
require_relative 'autoscaling_bootstrap/errors/elb'
|
19
|
+
require_relative 'autoscaling_bootstrap/alerts'
|
20
|
+
require_relative 'autoscaling_bootstrap/alerts/scaling'
|
21
|
+
require_relative 'autoscaling_bootstrap/alerts/monitoring'
|
22
|
+
require_relative 'autoscaling_bootstrap/aws'
|
23
|
+
require_relative 'autoscaling_bootstrap/AWS/elb'
|
24
|
+
require_relative 'autoscaling_bootstrap/AWS/ec2'
|
25
|
+
require_relative 'autoscaling_bootstrap/AWS/cloudwatch'
|
26
|
+
require_relative 'autoscaling_bootstrap/AWS/autoscaling'
|
27
|
+
require_relative 'autoscaling_bootstrap/AWS/Autoscaling/group'
|
28
|
+
require_relative 'autoscaling_bootstrap/AWS/Autoscaling/launch_config'
|
29
|
+
require_relative 'autoscaling_bootstrap/autoscaling_group'
|
30
|
+
require_relative 'autoscaling_bootstrap/launch_configuration'
|
31
|
+
require_relative 'autoscaling_bootstrap/version'
|
32
|
+
require_relative 'autoscaling_bootstrap/audit'
|
33
|
+
|
34
|
+
module Tapjoy
|
35
|
+
# Module for Autoscaling Bootstrap
|
36
|
+
module AutoscalingBootstrap
|
37
|
+
# This class is meant for class and instances variables used throughout
|
38
|
+
# the application.
|
39
|
+
class << self
|
40
|
+
attr_accessor :scaler_name, :config_name, :create_elb
|
41
|
+
attr_reader :elb_name
|
42
|
+
|
43
|
+
def elb_name=(str)
|
44
|
+
@elb_name = str
|
45
|
+
end
|
46
|
+
|
47
|
+
def policy
|
48
|
+
@policy = Tapjoy::AutoscalingBootstrap::Autoscaling::Policy.new
|
49
|
+
end
|
50
|
+
|
51
|
+
def group
|
52
|
+
@group = Tapjoy::AutoscalingBootstrap::Autoscaling::Group.new
|
53
|
+
end
|
54
|
+
|
55
|
+
def config
|
56
|
+
@config = Tapjoy::AutoscalingBootstrap::Autoscaling::Config.new
|
57
|
+
end
|
58
|
+
|
59
|
+
def cloudwatch
|
60
|
+
@cloudwatch = Tapjoy::AutoscalingBootstrap::CloudWatch.new
|
61
|
+
end
|
62
|
+
|
63
|
+
def config_dir
|
64
|
+
@config_dir ||= ENV['TASS_CONFIG_DIR'] || "#{ENV['HOME']}/.tass"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Base class for generic methods used throughout the gem
|
69
|
+
class Base
|
70
|
+
# Confirm that yaml is readable and then convert to hash
|
71
|
+
def load_yaml(filename)
|
72
|
+
abort("ERROR: '#{filename}' is not readable") unless File.readable?(filename)
|
73
|
+
Hash[YAML.load_file(filename)]
|
74
|
+
end
|
75
|
+
|
76
|
+
# Using variables passed in, generate user data file
|
77
|
+
def generate_user_data(config)
|
78
|
+
|
79
|
+
ERB.new(
|
80
|
+
File.new("#{config[:config_dir]}/userdata/#{config[:bootstrap_script]}").read,nil,'-'
|
81
|
+
).result(binding)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Check if we allow clobbering and need to clobber
|
85
|
+
def check_clobber(opts, config)
|
86
|
+
fail Tapjoy::AutoscalingBootstrap::Errors::ClobberRequired if check_as_clobber(**opts, **config)
|
87
|
+
fail Tapjoy::AutoscalingBootstrap::Errors::ELB::ClobberRequired if check_elb_clobber(**opts, **config)
|
88
|
+
puts "We don't need to clobber"
|
89
|
+
end
|
90
|
+
|
91
|
+
# Check autoscaling clobber
|
92
|
+
def check_as_clobber(create_as_group:, clobber_as:, **unused_values)
|
93
|
+
create_as_group && Tapjoy::AutoscalingBootstrap.group.exists && !clobber_as
|
94
|
+
end
|
95
|
+
|
96
|
+
# Check ELB clobber
|
97
|
+
def check_elb_clobber(create_elb:, clobber_elb:, **unused_values)
|
98
|
+
elb = Tapjoy::AutoscalingBootstrap::ELB.new
|
99
|
+
create_elb && elb.exists && !clobber_elb
|
100
|
+
end
|
101
|
+
|
102
|
+
# Get AWS Environment
|
103
|
+
def get_security_groups(config_dir, env, group)
|
104
|
+
|
105
|
+
# Check environment file
|
106
|
+
unless File.readable?("#{config_dir}/config/common/#{env}.yaml")
|
107
|
+
fail Tapjoy::AutoscalingBootstrap::Errors::InvalidEnvironment
|
108
|
+
end
|
109
|
+
|
110
|
+
security_groups = {security_groups: group.split(',')}
|
111
|
+
end
|
112
|
+
|
113
|
+
# Confirm config settings before running autoscaling code
|
114
|
+
def confirm_config(keypair:, zones:, security_groups:, instance_type:,
|
115
|
+
image_id:, iam_instance_profile:, prompt:, use_vpc: use_vpc,
|
116
|
+
vpc_subnets: nil, **unused_values)
|
117
|
+
|
118
|
+
elb_name = Tapjoy::AutoscalingBootstrap.elb_name
|
119
|
+
|
120
|
+
puts ' Preparing to configure the following autoscaling group:'
|
121
|
+
puts " Launch Config: #{Tapjoy::AutoscalingBootstrap.config_name}"
|
122
|
+
puts " Auto Scaler: #{Tapjoy::AutoscalingBootstrap.scaler_name}"
|
123
|
+
puts " ELB: #{elb_name}" unless elb_name.eql? 'NaE'
|
124
|
+
puts " Key Pair: #{keypair}"
|
125
|
+
puts " Zones: #{zones.join(',')}"
|
126
|
+
puts " Groups: #{security_groups.sort.join(',')}"
|
127
|
+
puts " Instance Type: #{instance_type}"
|
128
|
+
puts " Image ID: #{image_id}"
|
129
|
+
puts " IAM Role: #{iam_instance_profile}"
|
130
|
+
puts " VPC Subnets: #{vpc_subnets}" if use_vpc
|
131
|
+
|
132
|
+
puts "\n\nNOTE! Continuing may have adverse effects if you end up " \
|
133
|
+
"deleting an IN-USE PRODUCTION scaling group. Don't be dumb."
|
134
|
+
return true unless prompt
|
135
|
+
agree('Is this information correct? [y/n]')
|
136
|
+
end
|
137
|
+
|
138
|
+
# configure environment
|
139
|
+
def configure_environment(filename, env, config_dir)
|
140
|
+
defaults_hash = self.load_yaml("#{config_dir}/config/common/defaults.yaml")
|
141
|
+
facet_hash = self.load_yaml("#{config_dir}/config/clusters/#{filename}")
|
142
|
+
env_hash = self.load_yaml("#{config_dir}/config/common/#{env}.yaml")
|
143
|
+
|
144
|
+
new_config = defaults_hash.merge!(env_hash).merge(facet_hash)
|
145
|
+
new_config[:config_dir] = config_dir
|
146
|
+
aws_env = self.get_security_groups(config_dir, env, new_config[:group])
|
147
|
+
|
148
|
+
Tapjoy::AutoscalingBootstrap.scaler_name = "#{new_config[:name]}-group"
|
149
|
+
Tapjoy::AutoscalingBootstrap.config_name = "#{new_config[:name]}-config"
|
150
|
+
# If there's no ELB, then Not a ELB
|
151
|
+
puts new_config[:elb_name]
|
152
|
+
Tapjoy::AutoscalingBootstrap.elb_name = new_config[:elb_name] || 'NaE'
|
153
|
+
Tapjoy::AutoscalingBootstrap.create_elb = new_config[:create_elb]
|
154
|
+
user_data = self.generate_user_data(new_config)
|
155
|
+
return new_config, aws_env, user_data
|
156
|
+
end
|
157
|
+
|
158
|
+
# Exponential backup
|
159
|
+
def aws_wait(tries)
|
160
|
+
puts "Sleeping for #{2 ** tries}..."
|
161
|
+
sleep 2 ** tries
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|