Class: Jets::Resource::ApiGateway::RestApi::Routes::Change::Base

Inherits:
Object
  • Object
show all
Extended by:
Memoist
Includes:
AwsServices
Defined in:
lib/jets/resource/api_gateway/rest_api/routes/change/base.rb

Direct Known Subclasses

Variable

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

Instance Method Details

#controller_action_from_api(function_arn) ⇒ Object

TODO: If this hits the Lambda Rate limit, then list_functions also contains the Lambda function description. So we can paginate through list_functions results and store description from there if needed. Dont think this will be needed though because controller_action_from_string gets called most of the time. Also, user might be able to request their Lambda limit to be increased.



89
90
91
92
93
94
# File 'lib/jets/resource/api_gateway/rest_api/routes/change/base.rb', line 89

def controller_action_from_api(function_arn)
  desc = lambda_function_description(function_arn)
  controller, action = desc.split('#')
  controller = controller.underscore.sub(/_controller$/,'')
  [controller, action]
end

#controller_action_from_string(function_arn) ⇒ Object



96
97
98
99
100
101
102
103
# File 'lib/jets/resource/api_gateway/rest_api/routes/change/base.rb', line 96

def controller_action_from_string(function_arn)
  controller_action = function_arn.sub("#{Jets.project_namespace}-", '')
  md = controller_action.match(/(.*)_controller-(.*)/)
  controller = md[1]
  controller = controller.gsub('-','/')
  action = md[2]
  [controller, action]
end

#deployed_routesObject

Build up deployed routes from the existing CloudFormation resources.



7
8
9
10
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
38
39
40
41
# File 'lib/jets/resource/api_gateway/rest_api/routes/change/base.rb', line 7

def deployed_routes
  routes = []

  resources, position = [], true
  while position
    position = nil if position == true # start of loop
    resp = apigateway.get_resources(
      rest_api_id: rest_api_id,
      position: position,
    )
    resources += resp.items
    position = resp.position
  end

  resources.each do |resource|
    resource_methods = resource.resource_methods
    next if resource_methods.nil?

    resource_methods.each do |http_verb, resource_method|
      # puts "#{http_verb} #{resource.path} | resource.id #{resource.id}"
      # puts to(resource.id, http_verb)

      # Test changing config.cors and CloudFormation does an in-place update
      # on the resource. So no need to do bluegreen deployments for OPTIONS.
      next if http_verb == "OPTIONS"

      path = recreate_path(resource.path)
      method = http_verb.downcase.to_sym
      to = to(resource.id, http_verb)
      route = Jets::Route.new(path: path, method: method, to: to)
      routes << route
    end
  end
  routes
end

#get_controller_action(function_arn) ⇒ Object



76
77
78
79
80
81
82
# File 'lib/jets/resource/api_gateway/rest_api/routes/change/base.rb', line 76

def get_controller_action(function_arn)
  if function_arn.include?('_controller-')
    controller_action_from_string(function_arn)
  else
    controller_action_from_api(function_arn)
  end
end

#lambda_function_description(function_arn) ⇒ Object



105
106
107
108
# File 'lib/jets/resource/api_gateway/rest_api/routes/change/base.rb', line 105

def lambda_function_description(function_arn)
  resp = lambda.get_function(function_name: function_arn)
  resp.configuration.description # contains full info: PostsController#index
end

#method_uri(resource_id, http_method) ⇒ Object



55
56
57
58
59
60
61
62
# File 'lib/jets/resource/api_gateway/rest_api/routes/change/base.rb', line 55

def method_uri(resource_id, http_method)
  resp = apigateway.get_method(
    rest_api_id: rest_api_id,
    resource_id: resource_id,
    http_method: http_method
  )
  resp.method_integration.uri
end

#new_routesObject



125
126
127
# File 'lib/jets/resource/api_gateway/rest_api/routes/change/base.rb', line 125

def new_routes
  Jets::Router.routes
end

#recreate_path(path) ⇒ Object



44
45
46
47
48
# File 'lib/jets/resource/api_gateway/rest_api/routes/change/base.rb', line 44

def recreate_path(path)
  path = path.gsub(%r{^/},'')
  path = path.gsub(/{([^}]*)\+}/, '*\1')
  path.gsub(/{([^}]*)}/, ':\1')
end

#recreate_to(method_uri) ⇒ Object

Parses method uri and recreates a Route to argument. So:

"arn:aws:apigateway:us-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:us-west-2:112233445566:function:demo-test-posts_controller-new/invocations"

Returns:

posts#new


69
70
71
72
73
74
# File 'lib/jets/resource/api_gateway/rest_api/routes/change/base.rb', line 69

def recreate_to(method_uri)
  md = method_uri.match(/function:(.*)\//)
  function_arn = md[1] # IE: demo-dev-posts_controller-new
  controller, action = get_controller_action(function_arn)
  "#{controller}##{action}" # IE: posts#new
end

#rest_api_idObject

Duplicated in rest_api/change_detection.rb, base_path/role.rb, rest_api/routes.rb



111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/jets/resource/api_gateway/rest_api/routes/change/base.rb', line 111

def rest_api_id
  stack_name = Jets::Naming.parent_stack_name
  return "RestApi" unless stack_exists?(stack_name)

  stack = cfn.describe_stacks(stack_name: stack_name).stacks.first

  api_gateway_stack_arn = lookup(stack[:outputs], "ApiGateway")

  # resources = cfn.describe_stack_resources(stack_name: api_gateway_stack_arn).stack_resources
  stack = cfn.describe_stacks(stack_name: api_gateway_stack_arn).stacks.first
  lookup(stack[:outputs], "RestApi") # rest_api_id
end

#to(resource_id, http_method) ⇒ Object



50
51
52
53
# File 'lib/jets/resource/api_gateway/rest_api/routes/change/base.rb', line 50

def to(resource_id, http_method)
  uri = method_uri(resource_id, http_method)
  recreate_to(uri) unless uri.nil?
end