Shared resource needs output of APIGateway Rest API


#1

I’m developing a shared resource that needs the RestApi output from the APIGateway stack generated by Jets. How can I lookup the outputs of stacks generated by Jets ?

Something like this:

class ApigwUsagePlan < Jets::Stack
  resource(:UsagePlan, "AWS::ApiGateway::UsagePlan",
           UsagePlanName: "#{Jets.project_namespace}-usage-plan",
           ApiStages: [
               {
                   ApiId: ApiGateway.lookup(:RestApi),  # <<< This does not work
                   Stage: Jets.config.short_env
               }
           ]
  )
end

#2

I realize that the Stack::lookup function is not appropriate for use in this context. What I want is a dependency on the ApiGateway stack so I can use the RestApi output. Is there a way to make a shared/resource depend on the ApiGateway stack? In general is it possible for a shared/resource to depend on any of the generated resources ?

class ApigwUsagePlan < Jets::Stack
  depends_on :api_gateway      # <<< This does not work

  resource(:UsagePlan, "AWS::ApiGateway::UsagePlan",
           UsagePlanName: "#{Jets.project_namespace}-usage-plan",
           ApiStages: [
               {
                   ApiId: ref(:RestApi),  
                   Stage: Jets.config.short_env
               }
           ]
  )
end

This produces the following error during the build.

Building CloudFormation templates.
Traceback (most recent call last):
	37: from /Users/thampton/.rbenv/versions/2.5.5/bin/jets:23:in `<main>'
	36: from /Users/thampton/.rbenv/versions/2.5.5/bin/jets:23:in `load'
	35: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/jets-2.3.15/exe/jets:14:in `<top (required)>'
	34: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/jets-2.3.15/lib/jets/cli.rb:5:in `start'
	33: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/jets-2.3.15/lib/jets/cli.rb:28:in `start'
	32: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/jets-2.3.15/lib/jets/commands/base.rb:27:in `perform'
	31: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/jets-2.3.15/lib/jets/commands/base.rb:38:in `dispatch'
	30: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/thor-1.0.1/lib/thor.rb:392:in `dispatch'
	29: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/thor-1.0.1/lib/thor/invocation.rb:127:in `invoke_command'
	28: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/thor-1.0.1/lib/thor/command.rb:27:in `run'
	27: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/jets-2.3.15/lib/jets/commands/main.rb:12:in `build'
	26: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/jets-2.3.15/lib/jets/commands/build.rb:18:in `run'
	25: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/jets-2.3.15/lib/jets/commands/build.rb:23:in `build'
	24: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/jets-2.3.15/lib/jets/commands/build.rb:34:in `build_templates'
	23: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/jets-2.3.15/lib/jets/commands/build.rb:50:in `build_all_templates'
	22: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/jets-2.3.15/lib/jets/commands/build.rb:77:in `build_shared_resources_templates'
	21: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/jets-2.3.15/lib/jets/commands/build.rb:77:in `each'
	20: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/jets-2.3.15/lib/jets/commands/build.rb:78:in `block in build_shared_resources_templates'
	19: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/jets-2.3.15/lib/jets/cfn/builders/interface.rb:11:in `build'
	18: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/jets-2.3.15/lib/jets/stack.rb:37:in `build?'
	17: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/memoist-0.16.2/lib/memoist.rb:169:in `template'
	16: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/jets-2.3.15/lib/jets/stack.rb:60:in `template'
	15: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/memoist-0.16.2/lib/memoist.rb:169:in `template'
	14: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/jets-2.3.15/lib/jets/stack/builder.rb:11:in `template'
	13: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/jets-2.3.15/lib/jets/stack/builder.rb:19:in `build_section'
	12: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/jets-2.3.15/lib/jets/stack/builder.rb:35:in `build_elements'
	11: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/jets-2.3.15/lib/jets/stack/parameter/dsl.rb:9:in `parameters'
	10: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/memoist-0.16.2/lib/memoist.rb:169:in `add_depends_on_parameters'
	 9: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/jets-2.3.15/lib/jets/stack/parameter/dsl.rb:20:in `add_depends_on_parameters'
	 8: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/jets-2.3.15/lib/jets/stack/parameter/dsl.rb:20:in `each'
	 7: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/jets-2.3.15/lib/jets/stack/parameter/dsl.rb:21:in `block in add_depends_on_parameters'
	 6: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/jets-2.3.15/lib/jets/stack/parameter/dsl.rb:30:in `dependency_outputs'
	 5: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/activesupport-6.0.2.2/lib/active_support/core_ext/string/inflections.rb:68:in `constantize'
	 4: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/activesupport-6.0.2.2/lib/active_support/inflector/methods.rb:280:in `constantize'
	 3: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/activesupport-6.0.2.2/lib/active_support/inflector/methods.rb:280:in `inject'
	 2: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/activesupport-6.0.2.2/lib/active_support/inflector/methods.rb:280:in `each'
	 1: from /Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/activesupport-6.0.2.2/lib/active_support/inflector/methods.rb:282:in `block in constantize'
/Users/thampton/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/activesupport-6.0.2.2/lib/active_support/inflector/methods.rb:282:in `const_get': uninitialized constant ApiGateway (NameError)

#3

Very interesting. Nice use of shared resources. Thanks for the stack trace, it helped. Looks like a bug in Jets that doesn’t allow for the depends_on to with with internal stacks like the ApiGateway stack. :man_facepalming:t2:

Going to have to dig into this one. :face_with_monocle: Will consider PRs. No sweat either way of course. Hopefully, this at least answers the question.

In another note, think will deprecate the automagic camelization of logical ids and resource properties. Did this in another tool and it’s been great. Thoughts here https://lono.cloud/docs/conventions/camelizer/ Though the code looks less ruby-ish, it’s resulted in much more productivity. Less mental-context switching overhead.


#4

I also attempted creating the cognito user pool as a shared resource and then define an authorizer that depends on it. This example was very close to working. The cloudformation for the authorizer generated correctly, including the parameters from the :cognito stack. But the main stack did not pass the parameters to the authorizer child-stack.

class UserAuthorizer < ApplicationAuthorizer
  
depends_on :cognito

  authorizer(
      name: "#{Jets.project_namespace}-user-authorizer",
      identity_source: "Authorization", 
      type: :cognito_user_pools,
      provider_arns: [
          ref(:UserPoolArn),
          ref(:StaffPoolArn)
      ]
  )

end