Skip to content

External Parameters #170

@kornypoet

Description

@kornypoet

Problems

The current configuration system could use some attention. These are the arguments for changing its behavior:

  • Using binding.eval to set constants is an unsafe Ruby practice.
  • Because the above method was chosen, there are potential variable, method or constant name collisions possible (you could name your configuration keys too similar to library methods or existing constants).
  • There is no way to address the configuration as a whole, perhaps to implement environments, or turn all configuration keys into Parameter defaults.
  • The -D option is a powerful override for a specific key-value pair from the invocation, but right now it's interpreted as raw Ruby, and this should be guarded against.

Proposal

Implement an ExternalParameters configuration class. Move all of the logic of reading configuration files into this class, and remove the binding implementation. An instance of this class would be created for every time CloudFormation is invoked, and assigned to an easily recognizable method name. ExternalParameters would have all of the normal associated behavior of a regular Ruby hash. -D options on the command line turn into key-value entries in the configuration hash. Lastly, keep the old behavior around for a few releases with the option to disable/deprecate. In this case, the class would also assign the constants in the old way, to not break existing implementations.

Benefits

  • Clarified and standardized approach to configuration. All configuration behavior and logic is clean, and implemented in one dedicated class.
  • Access configuration as an entity, or separately as keys and values. Powerful and flexible.
  • Since the behavior is encapsulated, end users can extend the behavior to implement additional functionality, namely environments.
  • Configuration behaves as a Hash, with all of the benefits and expectations associated.
  • A single class is more easily testable.

Example

Some examples of how this would work (for discussion points, not a final implementation):

Keep existing behavior

Given a yaml file config.yaml:

---
FOO: foo
BAR: bar

Invoking cfndsl template.rb -y config.yaml

# template.rb
# Both behaviors
CloudFormation do
  ExternalParameters[:FOO] #=> 'foo'
  FOO #=> 'foo'
end

More flexible access

Given a yaml file config.yaml:

---
# Allow users to use lowercase config entries, something previously difficult to do
foo: foo
bar: bar

Invoking cfndsl template.rb -y config.yaml

# template.rb
CloudFormation do
  ExternalParameters[:foo] #=> 'foo'
  # We could easily implement indifferent access if desired
  ExternalParameters['foo'] #=> 'foo'
  # You can also address all configuration at the same time
  ExternalParameters.each_pair do |key, val|
    # ...
  end
end

Implementing environments

Given a yaml file config.yaml:

---
production:
   ...
development:
  ...

Invoking cfndsl template.rb -y config.yaml -D environment=production

# template.rb
CloudFormation do
  environment = ExternalParameters[:environment]
  config = ExternalParameters.fetch environment
  # use only production config
  # ...
end

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions