Skip to content

Use ENV with precedence over YAML configuration #39

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Unreleased Changes
------------------

* Issue - `Configuration` now takes environment variables with precedence over YAML configuration.

3.0.0 (2024-10-29)
------------------

Expand Down
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,13 @@ gem 'aws-sdk-rails', '~> 4'

A number of options are available to be set in
`Aws::SessionStore::DynamoDB::Configuration`, which is used throughout the
application. These options can be set directly by Ruby code, through
a YAML configuration file, or Environment variables, in order of precedence.
application. These options can be set directly in Ruby code, in ENV variables,
or in a YAML configuration file, in order of precedence.

The full set of options along with defaults can be found in the
[Configuration](https://docs.aws.amazon.com/sdk-for-ruby/aws-sessionstore-dynamodb/api/Aws/SessionStore/DynamoDB/Configuration.html)
documentation.

### YAML Configuration

You can create a YAML configuration file to set the options. The file must be
passed into Configuration as the `:config_file` option.

### Environment Options

All Configuration options can be loaded from the environment except for
Expand All @@ -62,6 +57,12 @@ The example below would be a valid way to set the session table name:

export DYNAMO_DB_SESSION_TABLE_NAME='your-table-name'

### YAML Configuration

You can create a YAML configuration file to set the options. The file must be
passed into Configuration as the `:config_file` option or with the
`DYNAMO_DB_SESSION_CONFIG_FILE` environment variable.

## Creating the session table

After installation and configuration, you must create the session table using
Expand Down
19 changes: 9 additions & 10 deletions lib/aws/session_store/dynamo_db/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

module Aws::SessionStore::DynamoDB
# This class provides a Configuration object for all DynamoDB session store operations
# by pulling configuration options from Runtime, a YAML file, the ENV, and default
# by pulling configuration options from Runtime, the ENV, a YAML file, and default
# settings, in that order.
#
# == Environment Variables
Expand Down Expand Up @@ -63,7 +63,7 @@ class Configuration
}.freeze

# Provides configuration object that allows access to options defined
# during Runtime, in a YAML file, in the ENV, and by default.
# during Runtime, in the ENV, in a YAML file, and by default.
#
# @option options [String] :table_name ("sessions") Name of the session table.
# @option options [String] :table_key ("session_id") The hash key of the session table.
Expand Down Expand Up @@ -99,8 +99,9 @@ class Configuration
# @option options [Aws::DynamoDB::Client] :dynamo_db_client (Aws::DynamoDB::Client.new)
# DynamoDB client used to perform database operations inside of the rack application.
def initialize(options = {})
opts = file_options(options).merge(options)
opts = options
opts = env_options.merge(opts)
opts = file_options(opts).merge(opts)
MEMBERS.each_pair do |opt_name, default_value|
opts[opt_name] = default_value unless opts.key?(opt_name)
end
Expand Down Expand Up @@ -145,13 +146,10 @@ def env_options
end

def parse_env_value(key)
Integer(ENV.fetch(key, nil))
val = ENV.fetch(key, nil)
Integer(val)
rescue ArgumentError
if ENV[key] == 'true' || ENV[key] == 'false'
ENV[key] == 'true'
else
ENV.fetch(key, nil)
end
%w[true false].include?(val) ? val == 'true' : val
end

# @return [Hash] File options.
Expand All @@ -168,7 +166,8 @@ def load_from_file(file_path)
require 'erb'
require 'yaml'
opts = YAML.safe_load(ERB.new(File.read(file_path)).result) || {}
opts.transform_keys(&:to_sym)
unsupported_keys = %i[dynamo_db_client error_handler config_file]
opts.transform_keys(&:to_sym).reject { |k, _| unsupported_keys.include?(k) }
end

def set_attributes(options)
Expand Down
75 changes: 53 additions & 22 deletions spec/aws/session_store/dynamo_db/configuration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@
}
end

def setup_env
def setup_env(options)
options.each do |k, v|
ENV["DYNAMO_DB_SESSION_#{k.to_s.upcase}"] = v.to_s
end
end

def teardown_env
def teardown_env(options)
options.each_key { |k| ENV.delete("DYNAMO_DB_SESSION_#{k.to_s.upcase}") }
end

Expand All @@ -41,44 +41,75 @@ def teardown_env
allow(Aws::DynamoDB::Client).to receive(:new).and_return(client)
end

it 'configures defaults without runtime, YAML or ENV options' do
it 'configures defaults without runtime, ENV, or YAML options' do
cfg = Aws::SessionStore::DynamoDB::Configuration.new
expect(cfg.to_hash).to include(defaults)
end

it 'configures with ENV with precedence over defaults' do
setup_env
cfg = Aws::SessionStore::DynamoDB::Configuration.new
expect(cfg.to_hash).to include(options)
teardown_env
it 'configures with YAML with precedence over defaults' do
Tempfile.create('dynamo_db_session_store.yml') do |f|
f << options.transform_keys(&:to_s).to_yaml
f.rewind
cfg = Aws::SessionStore::DynamoDB::Configuration.new(config_file: f.path)
expect(cfg.to_hash).to include(options)
end
end

it 'configures with ENV with precedence over YAML' do
setup_env(options)
Tempfile.create('dynamo_db_session_store.yml') do |f|
f << { table_name: 'OldTable', table_key: 'OldKey' }.transform_keys(&:to_s).to_yaml
f.rewind
cfg = Aws::SessionStore::DynamoDB::Configuration.new(config_file: f.path)
expect(cfg.to_hash).to include(options)
ensure
teardown_env(options)
end
end

it 'configures in code with full precedence' do
old = { table_name: 'OldTable', table_key: 'OldKey' }
setup_env(options.merge(old))
Tempfile.create('dynamo_db_session_store.yml') do |f|
f << old.transform_keys(&:to_s).to_yaml
f.rewind
cfg = Aws::SessionStore::DynamoDB::Configuration.new(options.merge(config_file: f.path))
expect(cfg.to_hash).to include(options)
ensure
teardown_env(options.merge(old))
end
end

it 'configs with YAML with precedence over ENV' do
setup_env
it 'allows for config file to be configured with ENV' do
Tempfile.create('dynamo_db_session_store.yml') do |f|
f << options.transform_keys(&:to_s).to_yaml
f.rewind
ENV['DYNAMO_DB_SESSION_CONFIG_FILE'] = f.path
cfg = Aws::SessionStore::DynamoDB::Configuration.new
ENV.delete('DYNAMO_DB_SESSION_CONFIG_FILE')
expect(cfg.to_hash).to include(options)
ensure
ENV.delete('DYNAMO_DB_SESSION_CONFIG_FILE')
end
teardown_env
end

it 'configures with runtime options with full precedence' do
setup_env
it 'ignores unsupported keys in ENV' do
ENV['DYNAMO_DB_SESSION_DYNAMO_DB_CLIENT'] = 'Client'
ENV['DYNAMO_DB_SESSION_ERROR_HANDLER'] = 'Handler'
cfg = Aws::SessionStore::DynamoDB::Configuration.new
expect(cfg.to_hash).to include(defaults)
ensure
ENV.delete('DYNAMO_DB_SESSION_DYNAMO_DB_CLIENT')
ENV.delete('DYNAMO_DB_SESSION_ERROR_HANDLER')
end

it 'ignores unsupported keys in YAML' do
Tempfile.create('dynamo_db_session_store.yml') do |f|
f << { table_name: 'OldTable', table_key: 'OldKey' }.transform_keys(&:to_s).to_yaml
options = { dynamo_db_client: 'Client', error_handler: 'Handler', config_file: 'File' }
f << options.transform_keys(&:to_s).to_yaml
f.rewind
cfg = Aws::SessionStore::DynamoDB::Configuration.new(
options.merge(
config_file: f.path
)
)
expect(cfg.to_hash).to include(options)
cfg = Aws::SessionStore::DynamoDB::Configuration.new(config_file: f.path)
expect(cfg.to_hash).to include(defaults.merge(config_file: f.path))
end
teardown_env
end

it 'raises an exception when wrong path for file' do
Expand Down
11 changes: 4 additions & 7 deletions spec/aws/session_store/dynamo_db/garbage_collection_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,14 @@

describe Aws::SessionStore::DynamoDB::GarbageCollection do
def items(min, max)
items = []
(min..max).each do |i|
items << { 'session_id' => { s: i.to_s } }
(min..max).map do |i|
{ 'session_id' => { s: i.to_s } }
end
items
end

def format_scan_result
items = []
(31..49).each do |i|
items << { 'session_id' => { s: i.to_s } }
items = (31..49).map do |i|
{ 'session_id' => { s: i.to_s } }
end

items.each_with_object([]) do |item, rqst_array|
Expand Down