kumo_config 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.buildkite/pipeline.yml +18 -0
- data/.gitignore +15 -0
- data/.rspec +2 -0
- data/.rubocop.yml +1156 -0
- data/Gemfile +4 -0
- data/README.md +121 -0
- data/Rakefile +2 -0
- data/VERSION +1 -0
- data/kumo_config.gemspec +25 -0
- data/lib/kumo_config/environment_config.rb +125 -0
- data/lib/kumo_config/file_loader.rb +38 -0
- data/lib/kumo_config.rb +1 -0
- data/script/build.sh +12 -0
- data/script/integration_test.sh +13 -0
- data/script/unit_test.sh +13 -0
- data/spec/integration/.gitkeep +0 -0
- data/spec/integration/config_spec.rb +67 -0
- data/spec/integration/fixtures/.gitkeep +0 -0
- data/spec/integration/fixtures/common.yml +2 -0
- data/spec/integration/fixtures/common_secrets.yml +11 -0
- data/spec/integration/fixtures/development.yml +1 -0
- data/spec/integration/fixtures/development_secrets.yml +5 -0
- data/spec/integration/fixtures/production.yml +2 -0
- data/spec/integration/fixtures/production_secrets.yml +11 -0
- data/spec/lib/environment_config_spec.rb +202 -0
- data/spec/lib/file_loader_spec.rb +64 -0
- data/spec/spec_helper.rb +28 -0
- metadata +153 -0
@@ -0,0 +1,202 @@
|
|
1
|
+
describe KumoConfig::EnvironmentConfig do
|
2
|
+
let(:env_name) { 'the_jungle' }
|
3
|
+
let(:config_dir_path) { '/var/config' }
|
4
|
+
let(:options) do
|
5
|
+
{
|
6
|
+
env_name: env_name,
|
7
|
+
config_path: config_dir_path,
|
8
|
+
params_template_file_path: params_template_file_path
|
9
|
+
}
|
10
|
+
end
|
11
|
+
let(:file_loader) { instance_double(KumoConfig::FileLoader) }
|
12
|
+
let(:file_loader_cloudformation) { instance_double(KumoConfig::FileLoader) }
|
13
|
+
let(:parameters_erb) { ERB.new("") }
|
14
|
+
let(:params_template_file_path) { 'junk.txt' }
|
15
|
+
let(:environment_config_file_name) { "#{env_name}.yml" }
|
16
|
+
let(:kms) { instance_double(KumoKi::KMS) }
|
17
|
+
let(:logger) { double(:test_logger, debug: nil) }
|
18
|
+
let(:environment_config) { described_class.new(options, logger) }
|
19
|
+
|
20
|
+
before do
|
21
|
+
allow(KumoConfig::FileLoader).to receive(:new).and_return(file_loader)
|
22
|
+
allow(KumoKi::KMS).to receive(:new).and_return(kms)
|
23
|
+
allow(file_loader).to receive(:load_erb).with(params_template_file_path).and_return(parameters_erb)
|
24
|
+
allow(File).to receive(:dirname).and_return('/tmp')
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'backward compatibility' do
|
28
|
+
context 'config_path' do
|
29
|
+
let(:options) do
|
30
|
+
{
|
31
|
+
env_name: env_name,
|
32
|
+
config_path: config_dir_path
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'will be used without complaint' do
|
37
|
+
expect(KumoConfig::FileLoader).to receive(:new).with(config_dir_path: config_dir_path).and_return(nil)
|
38
|
+
expect(logger).to receive(:warn).at_most(0).times
|
39
|
+
expect(logger).to receive(:fatal).at_most(0).times
|
40
|
+
described_class.new(options, logger)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'complains if config_path is not present'
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'config_dir_path' do
|
47
|
+
let(:options) do
|
48
|
+
{
|
49
|
+
env_name: env_name,
|
50
|
+
config_dir_path: config_dir_path
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'will be used if given and raise a deprecation warning' do
|
55
|
+
expect(KumoConfig::FileLoader).to receive(:new).with(config_dir_path: config_dir_path).and_return(nil)
|
56
|
+
expect(logger).to receive(:warn).with("[DEPRECATION] `:config_dir_path` is deprecated, please pass in `:config_path` instead")
|
57
|
+
described_class.new(options, logger)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'unit tests' do
|
63
|
+
describe '#get_binding' do
|
64
|
+
subject { environment_config.get_binding }
|
65
|
+
|
66
|
+
it 'returns a binding' do
|
67
|
+
expect(subject).to be_a(Binding)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "#config" do
|
72
|
+
subject { described_class.new(options, logger).config }
|
73
|
+
|
74
|
+
context 'injected config' do
|
75
|
+
|
76
|
+
let(:options) do
|
77
|
+
{
|
78
|
+
env_name: env_name,
|
79
|
+
config_path: config_dir_path,
|
80
|
+
params_template_file_path: params_template_file_path,
|
81
|
+
injected_config: { "injected" => "yes" }
|
82
|
+
}
|
83
|
+
end
|
84
|
+
|
85
|
+
let(:common_parameters) { { "stack_name" => "okonomiyaki" } }
|
86
|
+
it 'adds injected config to the config hash' do
|
87
|
+
expect(file_loader).to receive(:load_hash).with('common.yml').and_return(common_parameters)
|
88
|
+
expect(file_loader).to receive(:load_hash).with(environment_config_file_name).and_return({})
|
89
|
+
expect(file_loader).to receive(:load_hash).with("development.yml").and_return({})
|
90
|
+
|
91
|
+
expect(subject).to eq({ "stack_name" => "okonomiyaki", "injected" => "yes" })
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'common config' do
|
96
|
+
let(:common_parameters) { { "stack_name" => "okonomiyaki" } }
|
97
|
+
|
98
|
+
it 'creates a array containing an aws formatted parameter hash' do
|
99
|
+
expect(file_loader).to receive(:load_hash).with('common.yml').and_return(common_parameters)
|
100
|
+
expect(file_loader).to receive(:load_hash).with(environment_config_file_name).and_return({})
|
101
|
+
expect(file_loader).to receive(:load_hash).with("development.yml").and_return({})
|
102
|
+
|
103
|
+
expect(subject).to eq('stack_name' => 'okonomiyaki')
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context 'merging common and environment specific configurations' do
|
108
|
+
let(:environment_config) { {'image' => 'ami-5678'} }
|
109
|
+
let(:development_config) { {'image' => 'ami-9999'} }
|
110
|
+
|
111
|
+
context 'with environmental overrides' do
|
112
|
+
let(:parameter_template) { "image: <%= config['image'] %>" }
|
113
|
+
let(:common_config) { {'image' => 'ami-1234'} }
|
114
|
+
let(:env_name) { 'development' }
|
115
|
+
|
116
|
+
it 'replaces the common value with the env value' do
|
117
|
+
expect(file_loader).to receive(:load_hash).with('common.yml').and_return(common_config)
|
118
|
+
expect(file_loader).to receive(:load_hash).with(environment_config_file_name).and_return(environment_config)
|
119
|
+
expect(subject).to eq('image' => 'ami-5678')
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'falls back to a default environment if the requested one does not exist' do
|
124
|
+
expect(file_loader).to receive(:load_hash).with('common.yml').and_return({})
|
125
|
+
expect(file_loader).to receive(:load_hash).with("#{env_name}.yml").and_return({})
|
126
|
+
expect(file_loader).to receive(:load_hash).with("development.yml").and_return(development_config)
|
127
|
+
|
128
|
+
expect(subject).to eq('image' => 'ami-9999')
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe "#plain_text_secrets" do
|
134
|
+
subject { described_class.new(options, logger).plain_text_secrets }
|
135
|
+
|
136
|
+
let(:crypted_password) { 'lookatmyencryptedpasswords' }
|
137
|
+
let(:plain_text_password) { 'plain_text_password' }
|
138
|
+
let(:secrets) { { 'secret_password' => "[ENC,#{crypted_password}" } }
|
139
|
+
|
140
|
+
let(:crypted_env_password) { 'cryptedenvpassword' }
|
141
|
+
let(:plain_text_env_password) { 'plain_text_env_password' }
|
142
|
+
let(:env_secrets) { { 'secret_password' => "[ENC,#{crypted_env_password}"}}
|
143
|
+
|
144
|
+
before do
|
145
|
+
allow(kms).to receive(:decrypt).with(crypted_password).and_return(plain_text_password)
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'decrypts common secrets' do
|
149
|
+
allow(file_loader).to receive(:load_hash).with('common_secrets.yml').and_return(secrets)
|
150
|
+
allow(file_loader).to receive(:load_hash).with("#{env_name}_secrets.yml").and_return({})
|
151
|
+
allow(file_loader).to receive(:load_hash).with("development_secrets.yml").and_return({})
|
152
|
+
|
153
|
+
expect(subject).to eq('secret_password' => plain_text_password)
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'decrypts environment secrets' do
|
157
|
+
allow(file_loader).to receive(:load_hash).with('common_secrets.yml').and_return({})
|
158
|
+
allow(file_loader).to receive(:load_hash).with("#{env_name}_secrets.yml").and_return(secrets)
|
159
|
+
|
160
|
+
expect(subject).to eq('secret_password' => plain_text_password)
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'gives preference to environment secrets' do
|
164
|
+
allow(file_loader).to receive(:load_hash).with('common_secrets.yml').and_return(secrets)
|
165
|
+
allow(file_loader).to receive(:load_hash).with("#{env_name}_secrets.yml").and_return(env_secrets)
|
166
|
+
allow(kms).to receive(:decrypt).with(crypted_env_password).and_return(plain_text_env_password)
|
167
|
+
|
168
|
+
expect(subject).to eq('secret_password' => plain_text_env_password)
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'falls back to a default environment if the requested one does not exist' do
|
172
|
+
allow(file_loader).to receive(:load_hash).with('common_secrets.yml').and_return({})
|
173
|
+
allow(file_loader).to receive(:load_hash).with("#{env_name}_secrets.yml").and_return({})
|
174
|
+
expect(file_loader).to receive(:load_hash).with("development_secrets.yml").and_return(secrets)
|
175
|
+
|
176
|
+
expect(subject).to eq('secret_password' => plain_text_password)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
describe '#development?' do
|
181
|
+
%w(production staging).each do |environment|
|
182
|
+
it "returns false for #{environment}" do
|
183
|
+
expect(
|
184
|
+
described_class.new({
|
185
|
+
env_name: environment,
|
186
|
+
config_path: '',
|
187
|
+
params_template_file_path: ''}
|
188
|
+
).development?).to eq false
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'returns true for anything other than production or staging' do
|
193
|
+
expect(
|
194
|
+
described_class.new({
|
195
|
+
env_name: 'fred',
|
196
|
+
config_path: '',
|
197
|
+
params_template_file_path: ''}
|
198
|
+
).development?).to eq true
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
describe KumoConfig::FileLoader do
|
2
|
+
let(:config_dir_path) { '/the/garden/path' }
|
3
|
+
let(:options) { { config_dir_path: config_dir_path } }
|
4
|
+
let(:file_name) { 'environment.yml' }
|
5
|
+
let(:full_file_path) { config_dir_path + '/' + file_name }
|
6
|
+
|
7
|
+
describe "#load_erb" do
|
8
|
+
subject { KumoConfig::FileLoader.new(options).load_erb(file_name) }
|
9
|
+
|
10
|
+
context "when the requested erb file exits" do
|
11
|
+
let(:fake_erb_object) { double() }
|
12
|
+
let(:fake_file_handle) { double() }
|
13
|
+
|
14
|
+
it "loads the file and returns an ERB object" do
|
15
|
+
expect(File).to receive(:read).with("#{config_dir_path}/#{file_name}").and_return(fake_file_handle)
|
16
|
+
expect(ERB).to receive(:new).with(fake_file_handle).and_return(fake_erb_object)
|
17
|
+
expect(subject).to eq(fake_erb_object)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#load_hash" do
|
23
|
+
subject { KumoConfig::FileLoader.new(options).load_hash(file_name) }
|
24
|
+
|
25
|
+
context "when the file does not exist" do
|
26
|
+
it "returns an empty hash" do
|
27
|
+
expect(subject).to eq({})
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "when the file does exist" do
|
32
|
+
let(:file_contents) { 'key: value' }
|
33
|
+
|
34
|
+
it "populates a hash" do
|
35
|
+
expect(File).to receive(:read).with(full_file_path).and_return(file_contents)
|
36
|
+
expect(subject).to eq({ 'key' => 'value' })
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#load_hash when you set optional flag to false" do
|
42
|
+
let(:config_dir_path) { '/the/garden/path' }
|
43
|
+
let(:options) { { config_dir_path: config_dir_path } }
|
44
|
+
let(:file_name) { 'environment.yml' }
|
45
|
+
let(:full_file_path) { config_dir_path + '/' + file_name }
|
46
|
+
|
47
|
+
subject { KumoConfig::FileLoader.new(options).load_hash(file_name, false) }
|
48
|
+
|
49
|
+
context 'when the file does not exist' do
|
50
|
+
it 'raises an error' do
|
51
|
+
expect { subject }.to raise_error(Errno::ENOENT)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'when the file exists' do
|
56
|
+
let(:file_contents) { 'key: value' }
|
57
|
+
|
58
|
+
it 'populates a hash' do
|
59
|
+
expect(File).to receive(:read).with(full_file_path).and_return(file_contents)
|
60
|
+
expect(subject).to eq({ 'key' => 'value' })
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
ENV['RUBY_ENV'] ||= 'test'
|
2
|
+
require File.expand_path("../../lib/kumo_config.rb", __FILE__)
|
3
|
+
Dir[File.expand_path("../support/*.rb", __FILE__)].each {|file| require file }
|
4
|
+
|
5
|
+
RSpec.configure do |config|
|
6
|
+
# rspec-expectations config goes here. You can use an alternate
|
7
|
+
# assertion/expectation library such as wrong or the stdlib/minitest
|
8
|
+
# assertions if you prefer.
|
9
|
+
config.expect_with :rspec do |expectations|
|
10
|
+
# This option will default to `true` in RSpec 4. It makes the `description`
|
11
|
+
# and `failure_message` of custom matchers include text for helper methods
|
12
|
+
# defined using `chain`, e.g.:
|
13
|
+
# be_bigger_than(2).and_smaller_than(4).description
|
14
|
+
# # => "be bigger than 2 and smaller than 4"
|
15
|
+
# ...rather than:
|
16
|
+
# # => "be bigger than 2"
|
17
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
18
|
+
end
|
19
|
+
|
20
|
+
# rspec-mocks config goes here. You can use an alternate test double
|
21
|
+
# library (such as bogus or mocha) by changing the `mock_with` option here.
|
22
|
+
config.mock_with :rspec do |mocks|
|
23
|
+
# Prevents you from mocking or stubbing a method that does not exist on
|
24
|
+
# a real object. This is generally recommended, and will default to
|
25
|
+
# `true` in RSpec 4.
|
26
|
+
mocks.verify_partial_doubles = true
|
27
|
+
end
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: kumo_config
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Redbubble
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-09-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: kumo_ki
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.6'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.4'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.4'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.10'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.10'
|
83
|
+
description:
|
84
|
+
email:
|
85
|
+
- delivery-engineering@redbubble.com
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- ".buildkite/pipeline.yml"
|
91
|
+
- ".gitignore"
|
92
|
+
- ".rspec"
|
93
|
+
- ".rubocop.yml"
|
94
|
+
- Gemfile
|
95
|
+
- README.md
|
96
|
+
- Rakefile
|
97
|
+
- VERSION
|
98
|
+
- kumo_config.gemspec
|
99
|
+
- lib/kumo_config.rb
|
100
|
+
- lib/kumo_config/environment_config.rb
|
101
|
+
- lib/kumo_config/file_loader.rb
|
102
|
+
- script/build.sh
|
103
|
+
- script/integration_test.sh
|
104
|
+
- script/unit_test.sh
|
105
|
+
- spec/integration/.gitkeep
|
106
|
+
- spec/integration/config_spec.rb
|
107
|
+
- spec/integration/fixtures/.gitkeep
|
108
|
+
- spec/integration/fixtures/common.yml
|
109
|
+
- spec/integration/fixtures/common_secrets.yml
|
110
|
+
- spec/integration/fixtures/development.yml
|
111
|
+
- spec/integration/fixtures/development_secrets.yml
|
112
|
+
- spec/integration/fixtures/production.yml
|
113
|
+
- spec/integration/fixtures/production_secrets.yml
|
114
|
+
- spec/lib/environment_config_spec.rb
|
115
|
+
- spec/lib/file_loader_spec.rb
|
116
|
+
- spec/spec_helper.rb
|
117
|
+
homepage: http://redbubble.com
|
118
|
+
licenses:
|
119
|
+
- MIT
|
120
|
+
metadata: {}
|
121
|
+
post_install_message:
|
122
|
+
rdoc_options: []
|
123
|
+
require_paths:
|
124
|
+
- lib
|
125
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - ">="
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '0'
|
130
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
|
+
requirements:
|
132
|
+
- - ">="
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
135
|
+
requirements: []
|
136
|
+
rubyforge_project:
|
137
|
+
rubygems_version: 2.2.2
|
138
|
+
signing_key:
|
139
|
+
specification_version: 4
|
140
|
+
summary: A utility for reading Kumo configuration
|
141
|
+
test_files:
|
142
|
+
- spec/integration/.gitkeep
|
143
|
+
- spec/integration/config_spec.rb
|
144
|
+
- spec/integration/fixtures/.gitkeep
|
145
|
+
- spec/integration/fixtures/common.yml
|
146
|
+
- spec/integration/fixtures/common_secrets.yml
|
147
|
+
- spec/integration/fixtures/development.yml
|
148
|
+
- spec/integration/fixtures/development_secrets.yml
|
149
|
+
- spec/integration/fixtures/production.yml
|
150
|
+
- spec/integration/fixtures/production_secrets.yml
|
151
|
+
- spec/lib/environment_config_spec.rb
|
152
|
+
- spec/lib/file_loader_spec.rb
|
153
|
+
- spec/spec_helper.rb
|