consul_application_settings 0.1.4 → 1.0.0
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 +4 -4
- data/Gemfile.lock +2 -2
- data/README.md +21 -25
- data/consul_application_settings.gemspec +1 -1
- data/lib/consul_application_settings.rb +9 -17
- data/lib/consul_application_settings/configuration.rb +6 -6
- data/lib/consul_application_settings/consul_provider.rb +33 -0
- data/lib/consul_application_settings/file_provider.rb +54 -0
- data/lib/consul_application_settings/settings_provider.rb +16 -0
- data/lib/consul_application_settings/version.rb +1 -1
- metadata +7 -6
- data/lib/consul_application_settings/defaults.rb +0 -43
- data/lib/consul_application_settings/options.rb +0 -53
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b20ecf9e1eb2ea05e41f729b69082093305d3ce5291d8fb45a64f185ba8ae44f
|
4
|
+
data.tar.gz: ce5d16eb80ae0a9c0be78dda05d06e350546328d737ae1dd65309120f17fa814
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eac2795525ed07225d749c836781c5f9bebdfcaa55a8490d4cdca4ce2463db3130cd94e081cd87bd808743d7d1acf29729ccb5002000d5efc79a76b87a57bc0a
|
7
|
+
data.tar.gz: ed28b56badd89cbf5097ac4d061eadd43e7aa1da37aefec1693d5b17b4bb78996e9cc8c9f4b38564b6c0383ea77ac65f89c8b66bb4e7ba4af8c7e8c7820dc2d7
|
data/Gemfile.lock
CHANGED
@@ -24,7 +24,7 @@ GEM
|
|
24
24
|
ast (~> 2.4.0)
|
25
25
|
psych (3.1.0)
|
26
26
|
rainbow (3.0.0)
|
27
|
-
rake (
|
27
|
+
rake (13.0.1)
|
28
28
|
rspec (3.8.0)
|
29
29
|
rspec-core (~> 3.8.0)
|
30
30
|
rspec-expectations (~> 3.8.0)
|
@@ -62,7 +62,7 @@ PLATFORMS
|
|
62
62
|
DEPENDENCIES
|
63
63
|
bundler (~> 2.0)
|
64
64
|
consul_application_settings!
|
65
|
-
rake (~>
|
65
|
+
rake (~> 13.0)
|
66
66
|
rspec (~> 3.0)
|
67
67
|
rubocop (~> 0.66)
|
68
68
|
rubocop-rspec (~> 1.32.0)
|
data/README.md
CHANGED
@@ -23,7 +23,7 @@ Example use cases:
|
|
23
23
|
|
24
24
|
Gem reads any particular setting from consul and if it is missing tries to find value in YAML defaults file
|
25
25
|
|
26
|
-
**NOTE** Consul is requested every time you query the settings. Defaults YAML file loaded in memory and not changing.
|
26
|
+
**NOTE** Consul is requested every time you query the settings. Defaults YAML file is loaded in memory and is not changing.
|
27
27
|
|
28
28
|
## Installation
|
29
29
|
|
@@ -40,13 +40,17 @@ gem 'consul_application_settings'
|
|
40
40
|
At the load of application:
|
41
41
|
```ruby
|
42
42
|
ConsulApplicationSettings.configure do |config|
|
43
|
-
# Specify path to
|
44
|
-
config.
|
45
|
-
# Specify
|
46
|
-
config.
|
43
|
+
# Specify path to the base settings YML. Default: 'config/application_settings.yml'
|
44
|
+
config.base_file_path = Rails.root.join('config/my_settings.yml')
|
45
|
+
# Specify path to the local settings YML, which overrides the base file. Default: 'config/application_settings.local.yml'
|
46
|
+
config.local_file_path = Rails.root.join('config/my_settings.local.yml')
|
47
|
+
# Specify whether exceprion should be thrown on Consul connection errors. Default: false
|
48
|
+
config.disable_consul_connection_errors = true
|
47
49
|
end
|
48
50
|
|
49
51
|
APP_SETTINGS = ConsulApplicationSettings.load
|
52
|
+
# Specify path to settings both in YML files and Consul
|
53
|
+
AUTH_SETTIGNS = ConsulApplicationSettings.load('authentication')
|
50
54
|
```
|
51
55
|
|
52
56
|
**NOTE** For rails you can add this code to custom initializer `console_application_settings.rb` in `app/config/initializers`
|
@@ -55,7 +59,7 @@ APP_SETTINGS = ConsulApplicationSettings.load
|
|
55
59
|
|
56
60
|
### Settings structure
|
57
61
|
|
58
|
-
Assuming your defaults file in repository `config/
|
62
|
+
Assuming your defaults file in repository `config/application_settings.yml` looks like:
|
59
63
|
```yaml
|
60
64
|
staging:
|
61
65
|
my_cool_app:
|
@@ -98,15 +102,13 @@ Anywhere in your code base, after initialization, you can use
|
|
98
102
|
previously loaded settings to query any key by full path
|
99
103
|
|
100
104
|
```ruby
|
101
|
-
APP_SETTINGS
|
105
|
+
APP_SETTINGS['app_name'] # "MyCoolApp"
|
102
106
|
APP_SETTINGS.get(:hostname) # "https://mycoolapp.com"
|
103
107
|
|
104
108
|
APP_SETTINGS.get('integrations/database/user') # "app"
|
105
109
|
APP_SETTINGS['integrations/slack/enabled'] # true
|
106
110
|
```
|
107
111
|
|
108
|
-
**NOTE** Gem is pulling settings from consul with namespace but ignores namespace for defaults
|
109
|
-
|
110
112
|
### Nested settings
|
111
113
|
|
112
114
|
Assuming some part of your code needs to work with smaller part of settings -
|
@@ -114,36 +116,30 @@ gem provides interface to avoid duplicating absolute path
|
|
114
116
|
|
115
117
|
```ruby
|
116
118
|
# You can load subsettings from root object
|
117
|
-
db_settings = APP_SETTINGS.
|
118
|
-
db_settings.domain # "194.78.92.19"
|
119
|
-
db_settings['user']
|
120
|
-
|
121
|
-
# You can load subsettings from subsettings
|
122
|
-
integrations_settings = APP_SETTINGS.load_from('integrations')
|
123
|
-
slack_settings = integrations_settings.load_from('slack')
|
124
|
-
slack_settings.enabled # true
|
125
|
-
slack_settings.get('webhook_url') # "https://hooks.slack.com/services/XXXXXX/XXXXX/XXXXXXX"
|
119
|
+
db_settings = APP_SETTINGS.load('integrations/database')
|
120
|
+
db_settings.get(:domain) # "194.78.92.19"
|
121
|
+
db_settings['user'] # "app"
|
126
122
|
```
|
127
123
|
|
128
124
|
### Gem Configuration
|
129
125
|
You can configure gem with block:
|
130
126
|
```ruby
|
131
127
|
ConsulApplicationSettings.configure do |config|
|
132
|
-
config.
|
128
|
+
config.local_file_path = 'config/config.yml'
|
133
129
|
end
|
134
130
|
```
|
135
131
|
or one option at a time
|
136
132
|
```ruby
|
137
|
-
ConsulApplicationSettings.config.
|
133
|
+
ConsulApplicationSettings.config.local_file_path = 'config/config.yml'
|
138
134
|
```
|
139
135
|
|
140
136
|
All Gem configurations
|
141
137
|
|
142
|
-
| Configuration | Required | Default | Type | Description
|
143
|
-
|
144
|
-
|
|
145
|
-
|
|
146
|
-
| disable_consul_connection_errors | no |
|
138
|
+
| Configuration | Required | Default | Type | Description |
|
139
|
+
|----------------------------------|----------|-----------------------------------------|---------|------------------------------------------------------------------------------|
|
140
|
+
| base_file_path | no | 'config/application_settings.yml' | String | Path to the file with base settings |
|
141
|
+
| local_file_path | no | 'config/application_settings.local.yml' | String | Path to the file with local settings overriding the base settings |
|
142
|
+
| disable_consul_connection_errors | no | true | Boolean | Do not raise exception when consul is not available (useful for development) |
|
147
143
|
|
148
144
|
## Development
|
149
145
|
|
@@ -32,7 +32,7 @@ Gem::Specification.new do |spec|
|
|
32
32
|
spec.add_dependency 'diplomat', '~> 2.1.3'
|
33
33
|
|
34
34
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
35
|
-
spec.add_development_dependency 'rake', '~>
|
35
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
36
36
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
37
37
|
spec.add_development_dependency 'rubocop', '~> 0.66'
|
38
38
|
spec.add_development_dependency 'rubocop-rspec', '~> 1.32.0'
|
@@ -1,11 +1,11 @@
|
|
1
1
|
require 'consul_application_settings/version'
|
2
2
|
require 'consul_application_settings/configuration'
|
3
|
-
require 'consul_application_settings/
|
4
|
-
require 'consul_application_settings/
|
3
|
+
require 'consul_application_settings/consul_provider'
|
4
|
+
require 'consul_application_settings/file_provider'
|
5
|
+
require 'consul_application_settings/settings_provider'
|
5
6
|
require 'consul_application_settings/utils'
|
6
|
-
require 'diplomat'
|
7
7
|
|
8
|
-
#
|
8
|
+
# The gem provides possibility to load settings from Consul and automatically fall back to data stored in file system
|
9
9
|
module ConsulApplicationSettings
|
10
10
|
class Error < StandardError; end
|
11
11
|
|
@@ -16,19 +16,11 @@ module ConsulApplicationSettings
|
|
16
16
|
|
17
17
|
self.config ||= ConsulApplicationSettings::Configuration.new
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
self.defaults = ConsulApplicationSettings::Defaults.read(config.defaults_path)
|
23
|
-
end
|
24
|
-
|
25
|
-
def load_from(path)
|
26
|
-
settings_path = ConsulApplicationSettings::Utils.generate_path(config.namespace, path)
|
27
|
-
ConsulApplicationSettings::Options.new(settings_path, defaults)
|
28
|
-
end
|
19
|
+
def self.configure
|
20
|
+
yield(config)
|
21
|
+
end
|
29
22
|
|
30
|
-
|
31
|
-
|
32
|
-
end
|
23
|
+
def self.load(path = '')
|
24
|
+
SettingsProvider.new(path, config)
|
33
25
|
end
|
34
26
|
end
|
@@ -1,14 +1,14 @@
|
|
1
1
|
module ConsulApplicationSettings
|
2
2
|
# All gem configuration settings
|
3
3
|
class Configuration
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
attr_accessor :namespace
|
8
|
-
attr_accessor :disable_consul_connection_errors
|
4
|
+
DEFAULT_BASE_FILE_PATH = 'config/application_settings.yml'.freeze
|
5
|
+
DEFAULT_LOCAL_FILE_PATH = 'config/application_settings.local.yml'.freeze
|
6
|
+
attr_accessor :base_file_path, :local_file_path, :disable_consul_connection_errors
|
9
7
|
|
10
8
|
def initialize
|
11
|
-
|
9
|
+
@base_file_path = DEFAULT_BASE_FILE_PATH
|
10
|
+
@local_file_path = DEFAULT_LOCAL_FILE_PATH
|
11
|
+
@disable_consul_connection_errors = true
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'diplomat'
|
2
|
+
|
3
|
+
module ConsulApplicationSettings
|
4
|
+
# Provides access to settings stored in Consul
|
5
|
+
class ConsulProvider
|
6
|
+
def initialize(base_path, config)
|
7
|
+
@base_path = base_path
|
8
|
+
@config = config
|
9
|
+
end
|
10
|
+
|
11
|
+
def get(path)
|
12
|
+
value = fetch_value(path)
|
13
|
+
ConsulApplicationSettings::Utils.cast_consul_value(value)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def fetch_value(path)
|
19
|
+
full_path = generate_full_path(path)
|
20
|
+
Diplomat::Kv.get(full_path, {}, :return)
|
21
|
+
rescue SystemCallError, Faraday::ConnectionFailed, Diplomat::PathNotFound => e
|
22
|
+
raise e unless disable_consul_connection_errors?
|
23
|
+
end
|
24
|
+
|
25
|
+
def generate_full_path(path)
|
26
|
+
ConsulApplicationSettings::Utils.generate_path(@base_path, path)
|
27
|
+
end
|
28
|
+
|
29
|
+
def disable_consul_connection_errors?
|
30
|
+
@config.disable_consul_connection_errors
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module ConsulApplicationSettings
|
4
|
+
# Provides access to settings stored in file system with support of base and local files
|
5
|
+
class FileProvider
|
6
|
+
def initialize(base_path, config)
|
7
|
+
@base_path = base_path
|
8
|
+
@config = config
|
9
|
+
load
|
10
|
+
end
|
11
|
+
|
12
|
+
def get(path)
|
13
|
+
read_path(path).clone
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def load
|
19
|
+
base_yml = read_yml(base_file_path)
|
20
|
+
local_yml = read_yml(local_file_path)
|
21
|
+
@data = DeepMerge.deep_merge!(local_yml, base_yml, preserve_unmergeables: false, overwrite_arrays: true,
|
22
|
+
merge_nil_values: true)
|
23
|
+
end
|
24
|
+
|
25
|
+
def base_file_path
|
26
|
+
@config.base_file_path
|
27
|
+
end
|
28
|
+
|
29
|
+
def local_file_path
|
30
|
+
@config.local_file_path
|
31
|
+
end
|
32
|
+
|
33
|
+
def read_yml(path)
|
34
|
+
return {} unless File.exist?(path)
|
35
|
+
|
36
|
+
YAML.safe_load(IO.read(path))
|
37
|
+
rescue Psych::SyntaxError, Errno::ENOENT => e
|
38
|
+
raise ConsulApplicationSettings::Error, "Cannot read settings file at #{path}: #{e.message}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def read_path(path)
|
42
|
+
full_path = ConsulApplicationSettings::Utils.generate_path(@base_path, path)
|
43
|
+
parts = ConsulApplicationSettings::Utils.decompose_path(full_path)
|
44
|
+
parts.reduce(@data, &method(:read_value))
|
45
|
+
end
|
46
|
+
|
47
|
+
def read_value(hash, key)
|
48
|
+
raise ConsulApplicationSettings::Error, 'reading arrays not implemented' if hash.is_a? Array
|
49
|
+
return {} if hash.nil?
|
50
|
+
|
51
|
+
hash.fetch(key.to_s)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ConsulApplicationSettings
|
2
|
+
# Provides access to settings stored in Consul or in file system
|
3
|
+
class SettingsProvider
|
4
|
+
def initialize(base_path, config)
|
5
|
+
@consul_provider = ConsulProvider.new(base_path, config)
|
6
|
+
@file_provider = FileProvider.new(base_path, config)
|
7
|
+
end
|
8
|
+
|
9
|
+
def get(path)
|
10
|
+
consul_value = @consul_provider.get(path)
|
11
|
+
!consul_value.nil? && consul_value != '' ? consul_value : @file_provider.get(path)
|
12
|
+
end
|
13
|
+
|
14
|
+
alias [] get
|
15
|
+
end
|
16
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: consul_application_settings
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Volodymyr Mykhailyk
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-05-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: diplomat
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '13.0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '13.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rspec
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -136,8 +136,9 @@ files:
|
|
136
136
|
- consul_application_settings.gemspec
|
137
137
|
- lib/consul_application_settings.rb
|
138
138
|
- lib/consul_application_settings/configuration.rb
|
139
|
-
- lib/consul_application_settings/
|
140
|
-
- lib/consul_application_settings/
|
139
|
+
- lib/consul_application_settings/consul_provider.rb
|
140
|
+
- lib/consul_application_settings/file_provider.rb
|
141
|
+
- lib/consul_application_settings/settings_provider.rb
|
141
142
|
- lib/consul_application_settings/utils.rb
|
142
143
|
- lib/consul_application_settings/version.rb
|
143
144
|
homepage: https://github.com/matic-insurance/consul_application_settings
|
@@ -1,43 +0,0 @@
|
|
1
|
-
require 'yaml'
|
2
|
-
|
3
|
-
module ConsulApplicationSettings
|
4
|
-
# Reading default file from YAML file and providing interface to query them
|
5
|
-
class Defaults
|
6
|
-
attr_reader :contents
|
7
|
-
|
8
|
-
def initialize(hash)
|
9
|
-
@contents = hash
|
10
|
-
end
|
11
|
-
|
12
|
-
def get(name)
|
13
|
-
read_path(name, contents).clone
|
14
|
-
end
|
15
|
-
|
16
|
-
def load_from(path)
|
17
|
-
keys = ConsulApplicationSettings::Utils.decompose_path(path)
|
18
|
-
new_defaults = keys.reduce(contents) { |hash, key| read_path(key, hash, {}) }
|
19
|
-
self.class.new(new_defaults)
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.read(path)
|
23
|
-
new YAML.safe_load(IO.read(path))
|
24
|
-
rescue Psych::SyntaxError, Errno::ENOENT => e
|
25
|
-
raise ConsulApplicationSettings::Error, "Cannot read defaults file at #{path}: #{e.message}"
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def read_path(path, hash, default = nil)
|
31
|
-
parts = ConsulApplicationSettings::Utils.decompose_path(path)
|
32
|
-
result = parts.reduce(hash, &method(:read_value))
|
33
|
-
result || default
|
34
|
-
end
|
35
|
-
|
36
|
-
def read_value(hash, key)
|
37
|
-
raise ConsulApplicationSettings::Error, 'reading arrays not implemented' if hash.is_a? Array
|
38
|
-
return {} if hash.nil?
|
39
|
-
|
40
|
-
hash.fetch(key.to_s)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
|
3
|
-
module ConsulApplicationSettings
|
4
|
-
# Reads settings from consul or ask defaults for value
|
5
|
-
class Options
|
6
|
-
attr_reader :path, :defaults
|
7
|
-
|
8
|
-
def initialize(path, defaults)
|
9
|
-
@path = path
|
10
|
-
@defaults = defaults.load_from(path)
|
11
|
-
end
|
12
|
-
|
13
|
-
def load_from(new_path)
|
14
|
-
full_path = ConsulApplicationSettings::Utils.generate_path(path, new_path)
|
15
|
-
self.class.new(full_path, defaults)
|
16
|
-
end
|
17
|
-
|
18
|
-
def get(name)
|
19
|
-
consul_value = key_value(name)
|
20
|
-
if consul_value.nil? || consul_value.empty?
|
21
|
-
defaults.get(name)
|
22
|
-
else
|
23
|
-
ConsulApplicationSettings::Utils.cast_consul_value(consul_value)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def [](name)
|
28
|
-
get(name)
|
29
|
-
end
|
30
|
-
|
31
|
-
# rubocop:disable Style/MethodMissingSuper
|
32
|
-
def method_missing(name, *_args)
|
33
|
-
get(name)
|
34
|
-
end
|
35
|
-
# rubocop:enable Style/MethodMissingSuper
|
36
|
-
|
37
|
-
def respond_to_missing?(_name)
|
38
|
-
true
|
39
|
-
end
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
def key_value(name)
|
44
|
-
Diplomat::Kv.get(key_path(name), {}, :return)
|
45
|
-
rescue SystemCallError, Faraday::ConnectionFailed, Diplomat::PathNotFound => e
|
46
|
-
raise e unless ConsulApplicationSettings.config.disable_consul_connection_errors
|
47
|
-
end
|
48
|
-
|
49
|
-
def key_path(name)
|
50
|
-
ConsulApplicationSettings::Utils.generate_path(path, name)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|