lib/jets/lambda/dsl.rb in jets-0.8.18 vs lib/jets/lambda/dsl.rb in jets-0.9.0

- old
+ new

@@ -1,7 +1,11 @@ +require 'active_support/concern' + # Other dsl that rely on this must implement -# default_associated_resource: must return @resources +# +# default_associated_resource_definition +# module Jets::Lambda::Dsl extend ActiveSupport::Concern def lambda_functions self.class.lambda_functions @@ -128,47 +132,73 @@ def build_class_iam? !!(class_iam_policy || class_managed_iam_policy) end ############################# - # Main methood that registers resources associated with the Lambda function. + # Main method that registers resources associated with the Lambda function. # All resources methods lead here. - def resources(*definitions) - if definitions == [nil] # when resources called with no arguments - @resources || [] + def associated_resources(*definitions) + if definitions == [nil] # when associated_resources called with no arguments + @associated_resources || [] else - @resources ||= [] - @resources += definitions - @resources.flatten! + @associated_resources ||= [] + @associated_resources << Jets::Resource::Associated.new(definitions) + @associated_resources.flatten! end end - alias_method :resource, :resources + # User-friendly short resource method. Users will use this. + alias_method :resource, :associated_resources - # Main method that the convenience methods call for to create resources associated - # with the Lambda function. References the first resource and updates it inplace. - # Useful for associated resources that are meant to be declare and associated - # with only one Lambda function. Example: - # - # Config Rule <=> Lambda function is 1-to-1 - # - # Note: This methods calls default_associated_resource. The inheriting DSL class - # must implement default_associated_resource. The default_associated_resource should - # wrap another method that is nicely name so that the nicely name method is - # available in the DSL. Example: - # - # def default_associated_resource - # config_rule - # end - # - def update_properties(values={}) - @resources ||= default_associated_resource - definition = @resources.first # singleton - attributes = definition.values.first - attributes[:properties].merge!(values) - @resources + # Properties belonging to the associated resource + def associated_properties(options={}) + @associated_properties ||= {} + @associated_properties.deep_merge!(options) end + alias_method :associated_props, :associated_properties + # meta definition + def self.define_associated_properties(associated_properties) + associated_properties.each do |property| + # Example: + # def config_rule_name(value) + # associated_properties(config_rule_name: value) + # end + class_eval <<~CODE + def #{property}(value) + associated_properties(#{property}: value) + end + CODE + end + end + + # Loop back through the resources and add a counter to the end of the id + # to handle multiple events. + # Then replace @associated_resources entirely + def add_logical_id_counter + numbered_resources = [] + n = 1 + @associated_resources.map do |associated| + logical_id = associated.logical_id + attributes = associated.attributes + + logical_id = logical_id.sub(/\d+$/,'') + new_definition = { "#{logical_id}#{n}" => attributes } + numbered_resources << Jets::Resource::Associated.new(new_definition) + n += 1 + end + @associated_resources = numbered_resources + end + + def depends_on(*stacks) + if stacks == [] + @depends_on + else + @depends_on ||= [] + @depends_on += stacks + end + end + # meth is a Symbol def method_added(meth) return if %w[initialize method_missing].include?(meth.to_s) return unless public_method_defined?(meth) @@ -177,16 +207,30 @@ def register_task(meth, lang=:ruby) # Note: for anonymous classes like for app/functions self.name is "" # We adjust the class name when we build the functions later in # FunctionContstructor#adjust_tasks. + + # At this point we can use the current associated_properties and defined the + # associated resource with the Lambda function. + unless associated_properties.empty? + associated_resources(default_associated_resource_definition(meth)) + end + + # Unsure why but we have to use @associated_resources vs associated_resources + # associated_resources is always nil + if @associated_resources && @associated_resources.size > 1 + add_logical_id_counter + end + all_tasks[meth] = Jets::Lambda::Task.new(self.name, meth, - resources: @resources, # associated resources properties: @properties, # lambda function properties iam_policy: @iam_policy, managed_iam_policy: @managed_iam_policy, - lang: lang) + associated_resources: @associated_resources, + lang: lang, + replacements: replacements(meth)) # Done storing options, clear out for the next added method. clear_properties # Important to clear @properties at the end of registering outside of # register_task because register_task is overridden in Jets::Job::Dsl @@ -197,15 +241,20 @@ # So the Jets::Job::Dsl overrides some of the Jets::Lambda::Dsl behavior. true end + # Meant to be overridden to add more custom replacements based on the app class type + def replacements(meth) + {} + end + def clear_properties - @resources = nil @properties = nil @iam_policy = nil @managed_iam_policy = nil + @associated_resources = nil end # Returns the all tasks for this class with their method names as keys. # # ==== Returns @@ -250,8 +299,27 @@ end def node(meth) defpoly(:node, meth) end + end # end of class << self + end # end of included + + def self.add_custom_resource_extensions(base) + base_path = "#{Jets.root}/app/extensions" + unless ActiveSupport::Dependencies.autoload_paths.include?(base_path) + ActiveSupport::Dependencies.autoload_paths += [base_path] end + + Dir.glob("#{base_path}/**/*.rb").each do |path| + next unless File.file?(path) + + class_name = path.sub("#{base_path}/", '').sub(/\.rb/,'').classify + klass = class_name.constantize # autoload + base.extend(klass) + end + end + + def self.included(base) + add_custom_resource_extensions(base) end end