Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .rspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
--color
--require spec_helper
--format d
--order defined
2 changes: 1 addition & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ require 'bundler/gem_tasks'
require 'rspec/core/rake_task'

namespace :spec do
RSPEC_OPTS = ["--format", "nested", "--format", "html", "--out", "spec_result.html", "--colour"]
RSPEC_OPTS = ["--format", "documentation", "--format", "html", "--out", "spec_result.html", "--colour"]

RSpec::Core::RakeTask.new(:file) do |t|
t.rspec_opts = RSPEC_OPTS
Expand Down
24 changes: 15 additions & 9 deletions cf_deployer.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,23 @@ Gem::Specification.new do |gem|
gem.homepage = "http://github.com/manheim/cf_deployer"
gem.license = 'MIT'

gem.add_runtime_dependency 'aws-sdk','1.44.0'
gem.add_runtime_dependency 'aws-sdk-autoscaling', '~> 1.86'
gem.add_runtime_dependency 'aws-sdk-cloudformation', '~> 1.76'
gem.add_runtime_dependency 'aws-sdk-core', '~> 3.170'
gem.add_runtime_dependency 'aws-sdk-ec2', '~> 1.365'
gem.add_runtime_dependency 'aws-sdk-elasticloadbalancing', '~> 1.42'
gem.add_runtime_dependency 'aws-sdk-route53', '~> 1.71'
gem.add_runtime_dependency 'diffy'
gem.add_runtime_dependency 'json', '~> 2.5'
gem.add_runtime_dependency 'log4r'
gem.add_runtime_dependency 'thor'
gem.add_runtime_dependency 'rainbow'
gem.add_runtime_dependency 'diffy'
gem.add_development_dependency 'yard', '~> 0.8.7.6'
gem.add_development_dependency 'pry', '~> 0.10.1'
gem.add_development_dependency 'rspec', '2.14.1'
gem.add_development_dependency 'rake', '~> 10.3.0'
gem.add_development_dependency 'webmock', '~> 2.1.0'
gem.add_development_dependency 'vcr', '~> 2.9.3'
gem.add_runtime_dependency 'thor'
gem.add_development_dependency 'pry', '~> 0.13'
gem.add_development_dependency 'rake', '~> 13.0'
gem.add_development_dependency 'rspec', '3.10'
gem.add_development_dependency 'vcr', '~> 6.0'
gem.add_development_dependency 'webmock', '~> 3.11'
gem.add_development_dependency 'yard', '~> 0.9'

gem.files = `git ls-files`.split($\).reject {|f| f =~ /^samples\// }
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 10 additions & 6 deletions lib/cf_deployer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@
require 'set'
require 'time'
require 'json'
require 'yaml'
require 'timeout'
require 'aws-sdk'
require 'aws-sdk-autoscaling'
require 'aws-sdk-ec2'
require 'aws-sdk-core'
require 'aws-sdk-cloudformation'
require 'aws-sdk-elasticloadbalancing'
require 'aws-sdk-route53'
require 'erb'
require 'fileutils'
require 'log4r'
Expand Down Expand Up @@ -38,7 +44,8 @@

module CfDeployer

AWS.config(:max_retries => 20)
aws_config = Seahorse::Client::Configuration.new
aws_config.add_option(:max_retries, 20)

def self.config opts
config = self.parseconfig opts, false
Expand All @@ -50,19 +57,16 @@ def self.config opts

def self.deploy opts
config = self.parseconfig opts
# AWS.config(:logger => Logger.new($stdout))
Application.new(config).deploy
end

def self.runhook opts
config = self.parseconfig opts
# AWS.config(:logger => Logger.new($stdout))
Application.new(config).run_hook opts[:component].first, opts[:hook_name]
end

def self.destroy opts
config = self.parseconfig opts, false
# AWS.config(:logger => Logger.new($stdout))
Application.new(config).destroy
end

Expand Down Expand Up @@ -97,7 +101,7 @@ def self.kill_inactive opts
private

def self.parseconfig options, validate_inputs = true
AWS.config(:region => options[:region]) if options[:region]
Aws.config.update({region: options[:region]}) if options[:region]
options[:cli_overrides] = {:settings => options.delete(:settings), :inputs => options.delete(:inputs)}
config = ConfigLoader.new.load options
ConfigValidation.new.validate config, validate_inputs
Expand Down
2 changes: 1 addition & 1 deletion lib/cf_deployer/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def merged_options
def set_log_level
if options[:'log-level'] == 'aws-debug'
CfDeployer::Log.level = 'debug'
AWS.config :logger => Logger.new($stdout)
Aws.config.update(:logger => Logger.new($stdout))
else
CfDeployer::Log.level = options[:'log-level']
end
Expand Down
2 changes: 1 addition & 1 deletion lib/cf_deployer/config_loader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def load(options)

def load_yaml(text)
YAML.load text
rescue Psych::SyntaxError => e
rescue ::Psych::SyntaxError => e
error_document text
raise e
rescue
Expand Down
47 changes: 21 additions & 26 deletions lib/cf_deployer/driver/auto_scaling_group.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module Driver
class AutoScalingGroup
extend Forwardable

def_delegators :aws_group, :auto_scaling_instances, :ec2_instances, :load_balancers, :desired_capacity
def_delegators :aws_group, :instances, :desired_capacity, :load_balancer_names

attr_reader :group_name, :group

Expand All @@ -22,7 +22,7 @@ def warm_up desired
Log.info "warming up auto scaling group #{group_name} to #{desired}"

CfDeployer::Driver::DryRun.guard "Skipping ASG warmup" do
aws_group.set_desired_capacity desired
aws_group.set_desired_capacity({desired_capacity: desired})
wait_for_desired_capacity
end
end
Expand All @@ -38,14 +38,14 @@ def cool_down
Log.info "Cooling down #{group_name}"
CfDeployer::Driver::DryRun.guard "Skipping ASG cooldown" do
aws_group.update :min_size => 0, :max_size => 0
aws_group.set_desired_capacity 0
aws_group.set_desired_capacity({desired_capacity: 0})
end
end

def instance_statuses
instance_info = {}
ec2_instances.each do |instance|
instance_info[instance.id] = CfDeployer::Driver::Instance.new(instance).status
instances.each do |instance|
instance_info[instance.id] = CfDeployer::Driver::Instance.new(instance.id).status
end
instance_info
end
Expand All @@ -63,34 +63,25 @@ def desired_capacity_reached?
end

def healthy_instance_ids
instances = auto_scaling_instances.select do |instance|
_instances = instances.select do |instance|
'HEALTHY'.casecmp(instance.health_status) == 0
end
instances.map(&:id)
_instances.map(&:id)
end

def in_service_instance_ids
elbs = load_balancers
return [] if elbs.empty?

ids = elbs.collect(&:instances)
.collect(&:health)
.to_a
.collect { |elb_healths|
elb_healths.select { |health| health[:state] == 'InService' }
.map { |health| health[:instance].id }
}

ids.inject(:&)
elb_names = load_balancer_names

return [] if elb_names.empty?

elb_driver.in_service_instance_ids elb_names
end

def healthy_instance_count
AWS.memoize do
instances = healthy_instance_ids
instances &= in_service_instance_ids unless load_balancers.empty?
Log.info "Healthy instance count: #{instances.count}"
instances.count
end
instances = healthy_instance_ids
instances &= in_service_instance_ids unless load_balancer_names.empty?
Log.info "Healthy instance count: #{instances.count}"
instances.count
rescue => e
Log.error "Unable to determine healthy instance count due to error: #{e.message}"
-1
Expand All @@ -99,7 +90,11 @@ def healthy_instance_count
private

def aws_group
@my_group ||= AWS::AutoScaling.new.groups[group_name]
@my_group ||= Aws::AutoScaling::AutoScalingGroup.new(group_name)
end

def elb_driver
@elb_driver ||= Elb.new
end
end
end
Expand Down
41 changes: 22 additions & 19 deletions lib/cf_deployer/driver/cloud_formation_driver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,40 +7,40 @@ def initialize stack_name
end

def stack_exists?
aws_stack.exists?
!aws_stack.nil?
end

def create_stack template, opts
CfDeployer::Driver::DryRun.guard "Skipping create_stack" do
cloud_formation.stacks.create @stack_name, template, opts
cloud_formation.create_stack(opts.merge(stack_name: @stack_name, template_body: template))
end
end

def update_stack template, opts
begin
CfDeployer::Driver::DryRun.guard "Skipping update_stack" do
aws_stack.update opts.merge(:template => template)
cloud_formation.update_stack(opts.merge(stack_name: @stack_name, template_body: template))
end

rescue AWS::CloudFormation::Errors::ValidationError => e
if e.message =~ /No updates are to be performed/
Log.info e.message
return false
else
raise
end
rescue Aws::CloudFormation::Errors::ValidationError => e
Log.info e.message
return false
rescue => e
puts '*' * 80
puts e
raise
end

return !CfDeployer::Driver::DryRun.enabled?
end

def stack_status
aws_stack.status.downcase.to_sym
aws_stack&.stack_status&.downcase&.to_sym
end

def outputs
aws_stack.outputs.inject({}) do |memo, o|
memo[o.key] = o.value
memo[o.output_key] = o.output_value
memo
end
end
Expand All @@ -50,14 +50,14 @@ def parameters
end

def query_output key
output = aws_stack.outputs.find { |o| o.key == key }
output && output.value
output = aws_stack.outputs.find { |o| o.output_key == key }
output && output.output_value
end

def delete_stack
if stack_exists?
CfDeployer::Driver::DryRun.guard "Skipping create_stack" do
aws_stack.delete
cloud_formation.delete_stack(stack_name: @stack_name)
end
else
Log.info "Stack #{@stack_name} does not exist!"
Expand All @@ -66,7 +66,7 @@ def delete_stack

def resource_statuses
resources = {}
aws_stack.resource_summaries.each do |rs|
cloud_formation.list_stack_resources(stack_name: @stack_name).stack_resource_summaries.each do |rs|
resources[rs[:resource_type]] ||= {}
resources[rs[:resource_type]][rs[:physical_resource_id]] = rs[:resource_status]
end
Expand All @@ -80,14 +80,17 @@ def template
private

def cloud_formation
AWS::CloudFormation.new
Aws::CloudFormation::Client.new
end

def aws_stack
cloud_formation.stacks[@stack_name]
begin
cloud_formation.describe_stacks({stack_name: @stack_name}).stacks.first
rescue Aws::CloudFormation::Errors::ValidationError => e
return nil
end
end

end

end
end
13 changes: 10 additions & 3 deletions lib/cf_deployer/driver/elb_driver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,21 @@ module CfDeployer
module Driver
class Elb
def find_dns_and_zone_id elb_id
elb = elb_driver.load_balancers[elb_id]
{ :canonical_hosted_zone_name_id => elb.canonical_hosted_zone_name_id, :dns_name => elb.dns_name }
elb = elb_driver.describe_load_balancers(:load_balancer_names => [elb_id])&.load_balancer_descriptions&.first
{ :canonical_hosted_zone_name_id => elb&.canonical_hosted_zone_name_id, :dns_name => elb&.dns_name }
end

def in_service_instance_ids elb_ids
elb_ids.collect do |elb_id|
elb_driver.describe_instance_health(load_balancer_name: elb_id).instance_states
.collect{|instance| instance.state == 'InService' ? instance.instance_id : nil }.compact
end.inject(:&)
end

private

def elb_driver
AWS::ELB.new
@elb_driver ||= Aws::ElasticLoadBalancing::Client.new
end

end
Expand Down
5 changes: 3 additions & 2 deletions lib/cf_deployer/driver/instance.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@ def initialize instance_obj_or_id

def status
instance_info = { }
[:status, :public_ip_address, :private_ip_address, :image_id].each do |stat|
[:public_ip_address, :private_ip_address, :image_id].each do |stat|
instance_info[stat] = aws_instance.send(stat)
end
instance_info[:status] = aws_instance.state
instance_info[:key_pair] = aws_instance.key_pair.name
instance_info
end

def aws_instance
@instance_obj ||= AWS::EC2.new.instances[@id]
@instance_obj ||= Aws::EC2::Instance.new(@id)
end
end
end
Expand Down
Loading