Class: Jets::Commands::Deploy

Inherits:
Object
  • Object
show all
Extended by:
Memoist
Includes:
StackInfo
Defined in:
lib/jets/commands/deploy.rb

Instance Method Summary collapse

Methods included from StackInfo

#first_run?, #parent_stack_name, #s3_bucket, #stack_type

Methods included from AwsServices

#apigateway, #aws_lambda, #aws_options, #cfn, #dynamodb, #logs, #s3, #s3_resource, #sns, #sqs, #sts

Methods included from AwsServices::StackStatus

#lookup, #stack_exists?, #stack_in_progress?

Methods included from AwsServices::GlobalMemoist

included

Constructor Details

#initialize(options) ⇒ Deploy

Returns a new instance of Deploy.



7
8
9
# File 'lib/jets/commands/deploy.rb', line 7

def initialize(options)
  @options = options
end

Instance Method Details

#build_codeObject



60
61
62
# File 'lib/jets/commands/deploy.rb', line 60

def build_code
  Jets::Commands::Build.new(@options).build_code
end

#check_dev_modeObject



53
54
55
56
57
58
# File 'lib/jets/commands/deploy.rb', line 53

def check_dev_mode
  if File.exist?("#{Jets.root}/dev.mode")
    puts "The dev.mode file exists. Please removed it and run bundle update before you deploy.".color(:red)
    exit 1
  end
end

#create_s3_event_bucketsObject



39
40
41
42
43
44
# File 'lib/jets/commands/deploy.rb', line 39

def create_s3_event_buckets
  buckets = Jets::Job::Base.s3_events.keys
  buckets.each do |bucket|
    Jets::AwsServices::S3Bucket.ensure_exists(bucket)
  end
end

#delete_minimal_stackObject



46
47
48
49
50
51
# File 'lib/jets/commands/deploy.rb', line 46

def delete_minimal_stack
  puts "Existing stack is in ROLLBACK_COMPLETE state from a previous failed minimal deploy. Deleting stack and continuing."
  cfn.delete_stack(stack_name: stack_name)
  status.wait
  status.reset
end

#exit_unless_updateable!Object



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/jets/commands/deploy.rb', line 117

def exit_unless_updateable!
  return if ENV['JETS_FORCE_UPDATEABLE'] # useful for debugging if stack stack updating

  stack_name = Jets::Naming.parent_stack_name
  exists = stack_exists?(stack_name)
  return unless exists # continue because stack could be updating

  stack = cfn.describe_stacks(stack_name: stack_name).stacks.first
  status = stack["stack_status"]
  if status =~ /^ROLLBACK_/ ||
     status =~ /_IN_PROGRESS$/
    region = `aws configure get region`.strip rescue "us-east-1"
    url = "https://console.aws.amazon.com/cloudformation/home?region=#{region}#/stacks"
    puts "The parent stack of the #{Jets.config.project_name.color(:green)} project is not in an updateable state."
    puts "Stack name #{stack_name.color(:yellow)} status #{stack["stack_status"].color(:yellow)}"
    puts "Here's the CloudFormation url to check for more details #{url}"
    exit 1
  end
end

#find_stack(stack_name) ⇒ Object



104
105
106
107
108
109
110
111
112
113
114
# File 'lib/jets/commands/deploy.rb', line 104

def find_stack(stack_name)
  resp = cfn.describe_stacks(stack_name: stack_name)
  resp.stacks.first
rescue Aws::CloudFormation::Errors::ValidationError => e
  # example: Stack with id demo-dev does not exist
  if e.message =~ /Stack with/ && e.message =~ /does not exist/
    nil
  else
    raise
  end
end

#minimal_rollback_complete?Boolean

Checks for a few things before deciding to delete the parent stack

* Parent stack status status is ROLLBACK_COMPLETE
* Parent resources are in the DELETE_COMPLETE state

Returns:

  • (Boolean)


92
93
94
95
96
97
98
99
100
101
102
# File 'lib/jets/commands/deploy.rb', line 92

def minimal_rollback_complete?
  stack = find_stack(stack_name)
  return false unless stack

  return false unless stack.stack_status == 'ROLLBACK_COMPLETE'

  # Finally check if all the minimal resources in the parent template have been deleted
  resp = cfn.describe_stack_resources(stack_name: stack_name)
  resource_statuses = resp.stack_resources.map(&:resource_status).uniq
  resource_statuses == ['DELETE_COMPLETE']
end

#runObject



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/jets/commands/deploy.rb', line 11

def run
  deployment_env = Jets.config.project_namespace.color(:green)
  puts "Deploying to Lambda #{deployment_env} environment..."
  return if @options[:noop]

  check_dev_mode
  validate_routes!

  # deploy full nested stack when stack already exists
  # Delete existing rollback stack from previous bad minimal deploy
  delete_minimal_stack if minimal_rollback_complete?
  exit_unless_updateable! # Stack could be in a weird rollback state or in progress state

  if first_run?
    ship(stack_type: :minimal)
    Jets.application.reload_configs!
  end

  # Build code after the minimal stack because need s3 bucket for assets
  # on_aws? and s3_base_url logic
  # TODO: possible deploy hook point: before_build
  build_code

  # TODO: possible deploy hook point: before_ship
  create_s3_event_buckets
  ship(stack_type: :full, s3_bucket: s3_bucket)
end

#ship(stack_options) ⇒ Object



72
73
74
75
76
# File 'lib/jets/commands/deploy.rb', line 72

def ship(stack_options)
  options = @options.merge(stack_options) # includes stack_type and s3_bucket
  Jets::Commands::Build.new(options).build_templates
  Jets::Cfn::Ship.new(options).run
end

#stack_nameObject



83
84
85
# File 'lib/jets/commands/deploy.rb', line 83

def stack_name
  Jets::Naming.parent_stack_name
end

#statusObject



78
79
80
# File 'lib/jets/commands/deploy.rb', line 78

def status
  Jets::Cfn::Status.new(stack_name)
end

#validate_routes!Object



64
65
66
67
68
69
70
# File 'lib/jets/commands/deploy.rb', line 64

def validate_routes!
  valid = Jets::Router.validate_routes!
  unless valid
    puts "Deploy fail: The jets application contain invalid routes.".color(:red)
    exit 1
  end
end