Class: Jets::Cfn::Builder

Inherits:
Object
  • Object
show all
Extended by:
Memoist
Includes:
AwsServices
Defined in:
lib/jets/cfn/builder/nested.rb,
lib/jets/cfn/builder.rb,
lib/jets/cfn/builder/job.rb,
lib/jets/cfn/builder/rule.rb,
lib/jets/cfn/builder/parent.rb,
lib/jets/cfn/builder/shared.rb,
lib/jets/cfn/builder/function.rb,
lib/jets/cfn/builder/interface.rb,
lib/jets/cfn/builder/authorizer.rb,
lib/jets/cfn/builder/controller.rb,
lib/jets/cfn/builder/post_process.rb,
lib/jets/cfn/builder/one_controller.rb

Overview

post process the text so that “!Ref IamRole” => !Ref IamRole We strip the surrounding quotes

Defined Under Namespace

Modules: Api, Interface, Util Classes: Authorizer, Controller, Function, Job, Nested, OneController, Parent, PostProcess, Rule, Shared

Constant Summary collapse

APP_FOLDERS =
%w[authorizers controllers functions jobs rules]

Class Method Summary collapse

Instance Method Summary collapse

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) ⇒ Builder

Returns a new instance of Builder.



6
7
8
# File 'lib/jets/cfn/builder.rb', line 6

def initialize(options)
  @options = options
end

Class Method Details

.app_file?(path) ⇒ Boolean

Returns:

  • (Boolean)


149
150
151
152
153
154
155
156
# File 'lib/jets/cfn/builder.rb', line 149

def app_file?(path)
  return false unless File.extname(path) == ".rb"
  return false unless File.file?(path) unless Jets.env.test?
  return false if application_abstract_classes.detect { |p| path.include?(p) }
  return false if concerns?(path)
  return true if APP_FOLDERS.detect { |p| path.include?("app/#{p}") }
  false
end

.app_filesObject

Crucial that the Dir.pwd is in the tmp_code because for because Jets.boot set ups autoload_paths and this is how project classes are loaded. TODO: rework code so that Dir.pwd does not have to be in tmp_code for build to work.

app_files used to determine what CloudFormation templates to build. app_files also used to determine what handlers to build.



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/jets/cfn/builder.rb', line 131

def app_files
  paths = []
  expression = "#{Jets.root}/app/**/**/*.rb"
  Dir.glob(expression).each do |path|
    next unless app_file?(path)
    relative_path = path.sub("#{Jets.root}/", '') # rid of the Jets.root at beginning
    paths << relative_path
  end

  if Jets.config.prewarm.enable
    internal = File.expand_path("../internal", __dir__)
    paths << "#{internal}/app/jobs/jets/preheat_job.rb"
  end

  paths
end

.app_has_ruby?Boolean

Returns:

  • (Boolean)


199
200
201
202
203
204
205
206
# File 'lib/jets/cfn/builder.rb', line 199

def app_has_ruby?
  has_ruby = app_files.detect do |path|
    app_class = Jets::Klass.from_path(path)  # IE: PostsController, Jets::PublicController
    langs = app_class.definitions.map(&:lang)
    langs.include?(:ruby) && app_class != Jets::PreheatJob
  end
  !!has_ruby
end

.application_abstract_classesObject

Do not define lamda functions for abstract application parent classes. Examples:

application_controller.rb
application_job.rb
application_authorizer.rb


163
164
165
# File 'lib/jets/cfn/builder.rb', line 163

def application_abstract_classes
  APP_FOLDERS.map { |a| "application_#{a.singularize}.rb" }
end

.authorizer_filesObject



171
172
173
# File 'lib/jets/cfn/builder.rb', line 171

def authorizer_files
  app_files.select { |p| p.include?("app/authorizers") }
end

.concerns?(path) ⇒ Boolean

Returns:

  • (Boolean)


167
168
169
# File 'lib/jets/cfn/builder.rb', line 167

def concerns?(path)
  path =~ %r{app/\w+/concerns/}
end

.find_app_paths(app_path) ⇒ Object



179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/jets/cfn/builder.rb', line 179

def find_app_paths(app_path)
  paths = []
  expression = "#{Jets.root}/app/#{app_path}/**/*.rb"
  Dir.glob(expression).each do |path|
    return false unless File.file?(path)

    relative_path = path.sub("#{Jets.root}/", '')
    # Rids of the Jets.root at beginning
    paths << relative_path
  end
  paths
end

.poly_only?Boolean

Finds out of the app has polymorphic functions only and zero ruby functions. In this case, we can skip a lot of the ruby related building and speed up the deploy process.

Returns:

  • (Boolean)


195
196
197
# File 'lib/jets/cfn/builder.rb', line 195

def poly_only?
  !app_has_ruby? && !shared_has_ruby?
end

.router_has?(controller) ⇒ Boolean

Returns:

  • (Boolean)


221
222
223
# File 'lib/jets/cfn/builder.rb', line 221

def router_has?(controller)
  Jets::Router.has_controller?(controller)
end

.shared_filesObject



175
176
177
# File 'lib/jets/cfn/builder.rb', line 175

def shared_files
  find_app_paths("shared/resources")
end

.shared_has_ruby?Boolean

Returns:

  • (Boolean)


208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/jets/cfn/builder.rb', line 208

def shared_has_ruby?
  has_ruby = false
  Jets::Stack.subclasses.each do |klass|
    klass.functions.each do |fun|
      if fun.lang == :ruby
        has_ruby = true
        break
      end
    end
  end
  has_ruby
end

.tmp_code(full_build_path = false) ⇒ Object



225
226
227
# File 'lib/jets/cfn/builder.rb', line 225

def tmp_code(full_build_path=false)
  full_build_path ? "#{Jets.build_root}/stage/code" : "stage/code"
end

Instance Method Details

#app_filesObject



112
113
114
# File 'lib/jets/cfn/builder.rb', line 112

def app_files
  self.class.app_files
end

#authorizer?(path) ⇒ Boolean

Returns:

  • (Boolean)


104
105
106
# File 'lib/jets/cfn/builder.rb', line 104

def authorizer?(path)
  path.include?("app/authorizers")
end

#authorizer_filesObject



120
121
122
# File 'lib/jets/cfn/builder.rb', line 120

def authorizer_files
  self.class.authorizer_files
end

#buildObject



10
11
12
13
14
15
16
17
18
19
20
# File 'lib/jets/cfn/builder.rb', line 10

def build
  puts "Building CloudFormation templates"
  clean_templates
  build_minimal_parent_template
  if @options[:stack_type] == :full
    build_all_templates
    build_full_parent_template # must be called at the end
  end
  Jets::Router::State.save_apigw_state if ENV['JETS_API_STATE_DEBUG']
  puts "Built CloudFormation templates at #{Jets.build_root}/templates"
end

#build_all_templatesObject



26
27
28
29
30
31
32
33
34
35
36
# File 'lib/jets/cfn/builder.rb', line 26

def build_all_templates
  # CloudFormation templates
  # 1. Shared and authorizer templates - child templates needs them
  build_api_gateway_templates unless Jets::Router.no_routes?
  build_authorizer_templates # controllers can use these
  # 2. Child templates - parent template needs them
  build_one_lambda_for_all_controllers
  build_app_child_templates
  # 3. Child templates - parent template needs them
  build_shared_resources_templates
end

#build_api_gateway_templatesObject



42
43
44
45
46
47
48
# File 'lib/jets/cfn/builder.rb', line 42

def build_api_gateway_templates
  Api::Gateway.new(@options).build
  Api::Resources.build_pages(@options)
  Api::Methods.build_pages(@options)
  Api::Deployment.new(@options).build
  Api::Mapping.new(@options).build
end

#build_app_child_templatesObject



62
63
64
65
66
# File 'lib/jets/cfn/builder.rb', line 62

def build_app_child_templates
  app_files.each do |path|
    build_child_template(path)
  end
end

#build_authorizer_templatesObject



50
51
52
53
54
# File 'lib/jets/cfn/builder.rb', line 50

def build_authorizer_templates
  authorizer_files.each do |path|
    Authorizer.new(path).build
  end
end

#build_child_template(path) ⇒ Object

path: app/controllers/comments_controller.rb path: app/jobs/easy_job.rb



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/jets/cfn/builder.rb', line 76

def build_child_template(path)
  return if authorizer?(path) # AuthorizerBuilder is built earlier

  md = path.match(%r{app/(.*?)/}) # extract: controller, job or function
  app_class = md[1].classify

  if app_class == "Controller" && Jets.one_lambda_for_all_controllers? # app/controllers
    return
  end

  builder_class = "Jets::Cfn::Builder::#{app_class}".constantize

  app_class = Jets::Klass.from_path(path)
  if !Jets.gem_layer? && app_class == Jets::PreheatJob
    return # No prewarm when there's only poly functions and no gem layer
  end

  # Builder class fully qualified name:
  #   Controller => Jets::Cfn::Builder::Controller
  # Examples:
  #   Controller.new(PostsController).build
  #   Job.new(EasyJob).build
  #   Rule.new(CheckRule).build
  #   Function.new(Hello).build
  #   Function.new(HelloFunction).build
  builder_class.new(app_class).build
end

#build_full_parent_templateObject



38
39
40
# File 'lib/jets/cfn/builder.rb', line 38

def build_full_parent_template
  Parent.new(@options.merge(stack_type: :full)).build
end

#build_minimal_parent_templateObject



22
23
24
# File 'lib/jets/cfn/builder.rb', line 22

def build_minimal_parent_template
  Parent.new(@options.merge(stack_type: :minimal)).build
end

#build_one_lambda_for_all_controllersObject



56
57
58
59
60
# File 'lib/jets/cfn/builder.rb', line 56

def build_one_lambda_for_all_controllers
  return if Jets.config.mode == "job"
  return unless Jets.one_lambda_for_all_controllers?
  OneController.new(@options).build
end

#build_shared_resources_templatesObject



68
69
70
71
72
# File 'lib/jets/cfn/builder.rb', line 68

def build_shared_resources_templates
  Jets::Stack.subclasses.each do |subclass|
    Shared.new(subclass).build
  end
end

#clean_templatesObject



108
109
110
# File 'lib/jets/cfn/builder.rb', line 108

def clean_templates
  FileUtils.rm_rf("#{Jets.build_root}/templates")
end

#shared_filesObject



116
117
118
# File 'lib/jets/cfn/builder.rb', line 116

def shared_files
  self.class.shared_files
end