Class: Jets::Cfn::Builders::ApiGatewayBuilder

Inherits:
Object
  • Object
show all
Extended by:
Memoist
Includes:
AwsServices, Interface, Paged
Defined in:
lib/jets/cfn/builders/api_gateway_builder.rb

Constant Summary collapse

AWS_OUTPUT_LIMIT =
60

Instance Method Summary collapse

Methods included from AwsServices

#apigateway, #aws_lambda, #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

Methods included from Paged

#current_page, #current_page_number, #first_page, #pages, #push, #range, #turn_to_page

Methods included from Interface

#add_output, #add_outputs, #add_parameter, #add_parameters, #add_resource, #add_resources, #add_template_resource, #build, #cook_template, #post_process_template, #text

Constructor Details

#initialize(options = {}) ⇒ ApiGatewayBuilder

Returns a new instance of ApiGatewayBuilder.



10
11
12
13
# File 'lib/jets/cfn/builders/api_gateway_builder.rb', line 10

def initialize(options={})
  @options = options
  push(ActiveSupport::HashWithIndifferentAccess.new(Resources: {}))
end

Instance Method Details

#add_custom_domainObject



49
50
51
52
53
# File 'lib/jets/cfn/builders/api_gateway_builder.rb', line 49

def add_custom_domain
  return unless Jets.custom_domain?
  add_domain_name
  add_route53_dns if Jets.config.domain.route53
end

#add_domain_nameObject



55
56
57
58
59
# File 'lib/jets/cfn/builders/api_gateway_builder.rb', line 55

def add_domain_name
  domain_name = Jets::Resource::ApiGateway::DomainName.new
  add_resource(domain_name)
  add_outputs(domain_name.outputs)
end

#add_gateway_rest_apiObject

If the are routes in config/routes.rb add Gateway API in parent stack



39
40
41
42
43
44
45
46
47
# File 'lib/jets/cfn/builders/api_gateway_builder.rb', line 39

def add_gateway_rest_api
  rest_api = Jets::Resource::ApiGateway::RestApi.new
  add_resource(rest_api)
  add_outputs(rest_api.outputs)

  deployment = Jets::Resource::ApiGateway::Deployment.new
  outputs = deployment.outputs(true)
  add_output("RestApiUrl", Value: outputs["RestApiUrl"])
end

#add_gateway_routesObject

Adds route related Resources and Outputs



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/jets/cfn/builders/api_gateway_builder.rb', line 77

def add_gateway_routes
  # The routes required a Gateway Resource to contain them.
  # TODO: Support more routes. Right now outputing all routes in 1 template will hit the 60 routes limit.
  # Will have to either output them as a joined string or break this up to multiple templates.
  # http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cloudformation-limits.html
  # Outputs: Maximum number of outputs that you can declare in your AWS CloudFormation template. 60 outputs
  # Output name: Maximum size of an output name. 255 characters.
  #
  # Note we must use .all_paths, not .routes here because we need to
  # build the parent ApiGateway::Resource nodes also   
  indexed_paths.each do |path, page_number|
    homepage = path == ''
    next if homepage # handled by RootResourceId output already
    turn_to_page(page_number)
    resource = Jets::Resource::ApiGateway::Resource.new(path, internal: true, indexed_paths: indexed_paths)
    add_resource(resource)
    add_outputs_and_exports(resource.outputs)
    add_gateway_routes_parameters(resource, page_number)
  end
end

#add_gateway_routes_parameters(resource, page_number) ⇒ Object

TODO : consider refactoring this to make intent more clear



99
100
101
102
103
104
105
106
107
# File 'lib/jets/cfn/builders/api_gateway_builder.rb', line 99

def add_gateway_routes_parameters(resource, page_number)
  add_parameter('RestApi', Description: 'RestApi') 
  add_parameter('RootResourceId', Description: 'RootResourceId')
  resource.required_resources_from_parameters.each do |required_resource|
    add_parameter(required_resource[:logical_id], Description: required_resource[:logical_id])
    required_parameters_for_page = required_parameters[page_number] ||= []
    required_parameters_for_page.push required_resource
  end
end

#add_outputs_and_exports(attributes) ⇒ Object



115
116
117
118
119
120
# File 'lib/jets/cfn/builders/api_gateway_builder.rb', line 115

def add_outputs_and_exports(attributes) 
  attributes.each do |name,value|
    camelized_name = name.to_s.camelize
    add_output(camelized_name, value)
  end
end

#add_route53_dnsObject



61
62
63
64
65
# File 'lib/jets/cfn/builders/api_gateway_builder.rb', line 61

def add_route53_dns
  dns = Jets::Resource::Route53::RecordSet.new
  add_resource(dns)
  add_outputs(dns.outputs)
end

#composeObject

compose is an interface method



21
22
23
24
25
26
# File 'lib/jets/cfn/builders/api_gateway_builder.rb', line 21

def compose
  return unless @options[:templates] || @options[:stack_type] != :minimal

  populate_base_template
  add_gateway_routes
end

#indexed_pathsObject

Gateway routes are split across multiple CloudFormation templates because of a 60 Output limit by AWS. Having a resource and its corresponding parent resource ( :ParentId ) in the same template is not guaranteed so routes are indexed up front to allow us to determine how to find :ParentId ( !Ref vs !ImportValue )



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/jets/cfn/builders/api_gateway_builder.rb', line 125

def indexed_paths
  # indexed_paths is a Hash with key => path and value => page_number.  Each page number represents a separate 
  # template for the routes contained in it.
  # The reason for making the hash is we need to pass these indexed_paths to Jets::Resource::ApiGateway::Resource so it can
  # easily determine what page a parent path is in.
  # NOTE: that we are trying to keep Outputs to 60 and below, however, we are indexing "paths" here.  Currently there 
  # is a one to one relationship to paths and outputs for Jets::Resource::ApiGateway::Resource.  If that one to one changes
  # this solution will not work
  indexed_paths = Hash.new
  # root path == RootResource which comes off RestApi and is in ApiGateway0
  indexed_paths[''] = 0
  starting_index = 0
  page = 1
  loop do
    new_template # create new template here since we know we will need this page later
    Jets::Router.all_paths[starting_index, AWS_OUTPUT_LIMIT].each do |path|
      next if path.empty?
      indexed_paths[path] = page
    end
    starting_index += AWS_OUTPUT_LIMIT
    page += 1
    break if starting_index >= Jets::Router.all_paths.length
  end

  indexed_paths
end

#new_templateObject



153
154
155
# File 'lib/jets/cfn/builders/api_gateway_builder.rb', line 153

def new_template
  push(ActiveSupport::HashWithIndifferentAccess.new(Resources: {}))
end

#populate_base_templateObject

The base template holds RestApi, DomainName, and DnsRecord The base template will be added to the parent template as “ApiGateway” Giving the original name will limit the number of changes required for the AWS 60 output limit change.



71
72
73
74
# File 'lib/jets/cfn/builders/api_gateway_builder.rb', line 71

def populate_base_template
  add_gateway_rest_api
  add_custom_domain
end

#required_parametersObject

required_parameters will be used by the Parent Builder to know what parameters need to be passed to gateway template



111
112
113
# File 'lib/jets/cfn/builders/api_gateway_builder.rb', line 111

def required_parameters
  @required_parameters ||= []
end

#templateObject

template is an interface method



16
17
18
# File 'lib/jets/cfn/builders/api_gateway_builder.rb', line 16

def template 
  current_page
end

#template_pathObject

template_path is an interface method



29
30
31
# File 'lib/jets/cfn/builders/api_gateway_builder.rb', line 29

def template_path
  Jets::Naming.api_gateway_template_path("-#{current_page_number}")
end

#writeObject

do not bother writing a template if routes are empty



34
35
36
# File 'lib/jets/cfn/builders/api_gateway_builder.rb', line 34

def write
  super unless Jets::Router.routes.empty?
end