tass 0.1.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 +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
|