legion-settings 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: '09fab9f1b8877a7e4edd48838b81985de665106e'
4
+ data.tar.gz: 5f7fd30a767e066a87987ad0fdd04a3b605b1f87
5
+ SHA512:
6
+ metadata.gz: 1ccfdc0cee0c2983d381dca59260089b42141e600d97afaeaeaca94d093df0b35d88875526a5ed7528ec4416b29ae15ce753275e2574628f63b4c338ab285574
7
+ data.tar.gz: 45ed2014eb19bae521caad7cfd4cbe5baab5620d6adfb3138cc70a582f96e246ff9d1b872f67cb729d8b28cbc9f7cd7cbcc049e8c94c774fb5ca0c57043e57d1
@@ -0,0 +1,167 @@
1
+ version: 2 # use CircleCI 2.0
2
+ jobs:
3
+ "rubocop":
4
+ docker:
5
+ - image: circleci/ruby:2.4-node
6
+ steps:
7
+ - checkout
8
+ - run: gem install rubocop
9
+ - run:
10
+ name: Run Rubocop
11
+ command: rubocop
12
+ - store_test_results:
13
+ path: test_results
14
+ "ruby-2.0":
15
+ docker:
16
+ - image: circleci/ruby:2.0
17
+ steps:
18
+ - checkout
19
+ - run:
20
+ name: Bundle Install
21
+ command: bundle install
22
+ - run:
23
+ name: Run RSpec
24
+ command: bundle exec rspec --format progress --format RspecJunitFormatter -o test-results/rspec/results.xml
25
+ when: always
26
+ - store_test_results:
27
+ path: test-results
28
+ "ruby-2.1":
29
+ docker:
30
+ - image: circleci/ruby:2.1
31
+ steps:
32
+ - checkout
33
+ - run:
34
+ name: Bundle Install
35
+ command: bundle install
36
+ - run:
37
+ name: Run RSpec
38
+ command: bundle exec rspec --format progress --format RspecJunitFormatter -o test-results/rspec/results.xml
39
+ when: always
40
+ - store_test_results:
41
+ path: test-results
42
+ "ruby-2.2":
43
+ docker:
44
+ - image: circleci/ruby:2.2
45
+ steps:
46
+ - checkout
47
+ - run:
48
+ name: Bundle Install
49
+ command: bundle install
50
+ - run:
51
+ name: Run RSpec
52
+ command: bundle exec rspec --format progress --format RspecJunitFormatter -o test-results/rspec/results.xml
53
+ when: always
54
+ - store_test_results:
55
+ path: test-results
56
+
57
+ "ruby-2.3":
58
+ docker:
59
+ - image: circleci/ruby:2.3
60
+ steps:
61
+ - checkout
62
+ - run:
63
+ name: Bundle Install
64
+ command: bundle install
65
+ - run:
66
+ name: Run RSpec
67
+ command: bundle exec rspec --format progress --format RspecJunitFormatter -o test-results/rspec/results.xml
68
+ when: always
69
+ - store_test_results:
70
+ path: test-results
71
+
72
+ "ruby-2.4":
73
+ docker:
74
+ - image: circleci/ruby:2.4-node
75
+ steps:
76
+ - checkout
77
+ - run:
78
+ name: Bundle Install
79
+ command: bundle install
80
+ - run:
81
+ name: Run RSpec
82
+ command: bundle exec rspec --format progress --format RspecJunitFormatter -o test-results/rspec/results.xml
83
+ when: always
84
+ - store_test_results:
85
+ path: test-results
86
+ "ruby-2.5":
87
+ docker:
88
+ - image: circleci/ruby:2.5-node
89
+ steps:
90
+ - checkout
91
+ - run:
92
+ name: Bundle Install
93
+ command: bundle install
94
+ - run:
95
+ name: Run RSpec
96
+ command: bundle exec rspec --format progress --format RspecJunitFormatter -o test-results/rspec/results.xml
97
+ when: always
98
+ - store_test_results:
99
+ path: test-results
100
+ "ruby-2.6":
101
+ docker:
102
+ - image: circleci/ruby:2.6-node
103
+ steps:
104
+ - checkout
105
+ - run:
106
+ name: Bundle Install
107
+ command: bundle install
108
+ - run:
109
+ name: Run RSpec
110
+ command: bundle exec rspec --format progress --format RspecJunitFormatter -o test-results/rspec/results.xml
111
+ when: always
112
+ - store_test_results:
113
+ path: test-results
114
+ "jruby-9.2":
115
+ docker:
116
+ - image: circleci/jruby:9.2
117
+ steps:
118
+ - checkout
119
+ - run:
120
+ name: Bundle Install
121
+ command: bundle install
122
+ - run:
123
+ name: Run RSpec
124
+ command: bundle exec rspec --format progress --format RspecJunitFormatter -o test-results/rspec/results.xml
125
+ when: always
126
+ - store_test_results:
127
+ path: test-results
128
+
129
+ workflows:
130
+ version: 2
131
+ cop_rake_deploy:
132
+ jobs:
133
+ - rubocop
134
+ # - ruby-2.2:
135
+ # requires:
136
+ # - ruby-2.4
137
+ # filters:
138
+ # branches:
139
+ # only: /\bdevelop\b|\bmaster\b/
140
+ - ruby-2.3:
141
+ requires:
142
+ - ruby-2.4
143
+ filters:
144
+ branches:
145
+ only: /\bdevelop\b|\bmaster\b/
146
+ - ruby-2.4:
147
+ requires:
148
+ - rubocop
149
+ - ruby-2.5:
150
+ requires:
151
+ - ruby-2.4
152
+ filters:
153
+ branches:
154
+ only: /\bdevelop\b|\bmaster\b/
155
+ - ruby-2.6:
156
+ requires:
157
+ - ruby-2.4
158
+ filters:
159
+ branches:
160
+ only: /\bdevelop\b|\bmaster\b/
161
+ # - jruby-9.2:
162
+ # requires:
163
+ # - ruby-2.2
164
+ # - ruby-2.3
165
+ # - ruby-2.4
166
+ # - ruby-2.5
167
+ # - ruby-2.6
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /rspec/
11
+ /test-results/
12
+
13
+ # rspec failure tracking
14
+ .rspec_status
15
+
data/.rubocop.yml ADDED
@@ -0,0 +1,25 @@
1
+ Metrics/LineLength:
2
+ Max: 120
3
+ Metrics/MethodLength:
4
+ Max: 30
5
+ Metrics/ClassLength:
6
+ Max: 1500
7
+ Metrics/BlockLength:
8
+ Max: 50
9
+ Layout/SpaceAroundEqualsInParameterDefault:
10
+ EnforcedStyle: space
11
+ Style/SymbolArray:
12
+ Enabled: true
13
+ Layout/AlignHash:
14
+ EnforcedHashRocketStyle: table
15
+ EnforcedColonStyle: table
16
+ Style/HashSyntax:
17
+ EnforcedStyle: ruby19_no_mixed_keys
18
+ Style/Documentation:
19
+ Enabled: false
20
+ AllCops:
21
+ TargetRubyVersion: 2.4
22
+ Style/FrozenStringLiteralComment:
23
+ Enabled: false
24
+ Naming/FileName:
25
+ Enabled: false
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in legion-settings.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Esity
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,42 @@
1
+ # Legion::Settings
2
+
3
+ Legion::Settings is part of the Legion Framework
4
+
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'legion-settings'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install legion-settings
21
+
22
+ ## Usage
23
+
24
+ This library is utilized by Legion to load config files
25
+
26
+ ## Gem
27
+
28
+ This gem can be viewed and download from [RubyGems - Legion-Settings](https://rubygems.org/gems/legion-settings)
29
+
30
+ ## Development
31
+
32
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
33
+
34
+ To install this gem onto your local machine, run `bundle exec install`.
35
+
36
+ ## Contributing
37
+
38
+ Bug reports and pull requests are welcome on GitHub at https://bitbucket.org/legion-io/legion-settings/issues This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
39
+
40
+ ## License
41
+
42
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'legion/settings'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require 'irb'
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,39 @@
1
+ image: ruby:2.4.0
2
+
3
+ pipelines:
4
+ branches:
5
+ master:
6
+ - step:
7
+ caches:
8
+ - bundler
9
+ script:
10
+ - gem install bundle rubocop
11
+ - bundle install
12
+ - rubocop
13
+ - rake
14
+ - step:
15
+ name: Deploy to test gem server
16
+ deployment: test
17
+ script:
18
+ - gem install bundle geminabox
19
+ - bundle install
20
+ - gem build legion-settings.gemspec
21
+ - gem inabox legion-settings*.gem -g https://gems.whonodes.org/ -o
22
+ - step:
23
+ name: Deploy to RubyGems
24
+ deployment: production
25
+ trigger: manual
26
+ script:
27
+ - gem build legion-settings.gemspec
28
+ default:
29
+ - step:
30
+ caches:
31
+ - bundler
32
+ script:
33
+ - gem install bundle rubocop
34
+ - bundle install
35
+ - rubocop
36
+ - rake
37
+ definitions:
38
+ caches:
39
+ bundler: vendor/bundle
@@ -0,0 +1,34 @@
1
+ lib = File.expand_path('lib', __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'legion/settings/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'legion-settings'
7
+ spec.version = Legion::Settings::VERSION
8
+ spec.authors = ['Esity']
9
+ spec.email = ['matthewdiverson@gmail.com']
10
+
11
+ spec.summary = 'Used to load the json settings files'
12
+ spec.description = "Based on Sensu's implementation of settings"
13
+ spec.homepage = 'https://bitbucket.org/whonodes/legion-settings'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.bindir = 'exe'
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ['lib']
22
+
23
+ spec.add_development_dependency 'bundler', '~> 1'
24
+ spec.add_development_dependency 'codecov', '~> 0'
25
+ spec.add_development_dependency 'rake', '~> 10.0'
26
+ spec.add_development_dependency 'rspec', '~> 3.0'
27
+ spec.add_development_dependency 'rspec_junit_formatter', '~> 0'
28
+ if RUBY_ENGINE == 'jruby'
29
+ spec.add_dependency('legion-json-jruby', '~> 0.1')
30
+ else
31
+ spec.add_dependency('legion-json', '~> 0.1')
32
+ end
33
+ spec.add_dependency 'legion-logging', '~> 0.1'
34
+ end
@@ -0,0 +1,40 @@
1
+ require 'legion/json'
2
+ require 'legion/settings/version'
3
+ require 'legion/json/parse_error'
4
+ require 'legion/settings/loader'
5
+
6
+ module Legion
7
+ # Base Legion::Settings module
8
+ module Settings
9
+ # Base settings, needs to be refactored
10
+ class << self
11
+ attr_accessor :loader
12
+ def load(options = {})
13
+ @loader = Legion::Settings::Loader.new
14
+ @loader.load_env
15
+ @loader.load_file(options[:config_file]) if options[:config_file]
16
+ @loader.load_directory(options[:config_dir]) if options[:config_dir]
17
+ options[:config_dirs]&.each do |directory|
18
+ @loader.load_directory(directory)
19
+ end
20
+ @loader
21
+ end
22
+
23
+ def get(options = {})
24
+ @loader || @loader = load(options)
25
+ end
26
+
27
+ def [](key)
28
+ Legion::Logging.warn('Legion::Settings was not loading, auto loading now!') if @loader.nil?
29
+ @loader = load if @loader.nil?
30
+ @loader[key]
31
+ end
32
+
33
+ def set_prop(key, value)
34
+ Legion::Logging.warn('Legion::Settings was not loading, auto loading now!') if @loader.nil?
35
+ @loader = load if @loader.nil?
36
+ @loader[key] = value
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,5 @@
1
+ module Legion
2
+ module Settings
3
+ CATEGORIES = [:interations].freeze
4
+ end
5
+ end
@@ -0,0 +1,282 @@
1
+ module Legion
2
+ module Settings
3
+ # This is the main settings class, needs refactor
4
+ class Loader
5
+ # This is the standard error
6
+ class Error < RuntimeError; end
7
+
8
+ attr_reader :warnings
9
+ attr_reader :errors
10
+ attr_reader :loaded_files
11
+
12
+ def initialize
13
+ @warnings = []
14
+ @errors = []
15
+ @settings = default_settings
16
+ @indifferent_access = false
17
+ @loaded_files = []
18
+ self.class.create_category_methods
19
+ end
20
+
21
+ def client_defaults
22
+ {
23
+ name: system_hostname,
24
+ address: system_address
25
+ }
26
+ end
27
+
28
+ def default_settings
29
+ default = {
30
+ client: {},
31
+ legion: {
32
+ spawn: {
33
+ limit: 12
34
+ }
35
+ },
36
+ transport: {
37
+ rabbitmq: {
38
+ user: 'guest',
39
+ password: 'guest',
40
+ host: '127.0.0.1'
41
+ }
42
+ },
43
+ data: {
44
+ mysql: {
45
+ user: 'legion',
46
+ password: 'legion',
47
+ max_connections: 20,
48
+ database: 'legion',
49
+ host: '127.0.0.1',
50
+ debug: false
51
+ }
52
+ }
53
+ }
54
+ default[:client] = client_defaults if %w[client rspec].include?(legion_service_name)
55
+ default
56
+ end
57
+
58
+ def self.create_category_methods
59
+ # CATEGORIES.each do |category|
60
+ # define_method(category) do
61
+ # setting_category(category)
62
+ # end
63
+ # method_name = category.to_s.chop + "_exists?"
64
+ # define_method(method_name.to_sym) do |name|
65
+ # definition_exists?(category, name)
66
+ # end
67
+ # end
68
+ end
69
+
70
+ def to_hash
71
+ unless @indifferent_access
72
+ indifferent_access!
73
+ @hexdigest = nil
74
+ end
75
+ @settings
76
+ end
77
+
78
+ def [](key)
79
+ to_hash[key]
80
+ end
81
+
82
+ def hexdigest
83
+ if @hexdigest && @indifferent_access
84
+ @hexdigest
85
+ else
86
+ hash = case legion_service_name
87
+ when 'client', 'rspec'
88
+ to_hash
89
+ else
90
+ to_hash.reject do |key, _value|
91
+ key.to_s == 'client'
92
+ end
93
+ end
94
+ @hexdigest = Digest::SHA256.hexdigest(hash.to_s)
95
+ end
96
+ end
97
+
98
+ def load_env
99
+ load_api_env
100
+ end
101
+
102
+ def load_file(file)
103
+ Legion::Logging.debug("Trying to load file #{file}")
104
+ if File.file?(file) && File.readable?(file)
105
+ begin
106
+ contents = read_config_file(file)
107
+ config = contents.empty? ? {} : Legion::JSON.load(contents)
108
+ merged = deep_merge(@settings, config)
109
+ deep_diff(@settings, merged) unless @loaded_files.empty?
110
+ @settings = merged
111
+ # @indifferent_access = false
112
+ @loaded_files << file
113
+ rescue Legion::JSON::ParseError => error
114
+ Legion::Logging.error('config file must be valid json')
115
+ Legion::Logging.debug("file:#{file}, error: #{error}")
116
+ end
117
+ else
118
+ Legion::Logging.warn("Config file does not exist or is not readable file:#{file}")
119
+ end
120
+ end
121
+
122
+ def load_directory(directory)
123
+ warning('loading config files from directory', directory: directory)
124
+ path = directory.gsub(/\\(?=\S)/, '/')
125
+ if File.readable?(path) && File.executable?(path)
126
+ Dir.glob(File.join(path, '**{,/*/**}/*.json')).uniq.each do |file|
127
+ load_file(file)
128
+ end
129
+ else
130
+ load_error('insufficient permissions for loading', directory: directory)
131
+ end
132
+ end
133
+
134
+ def load_client_overrides
135
+ @settings[:client][:subscriptions] ||= []
136
+ if @settings[:client][:subscriptions].is_a?(Array)
137
+ @settings[:client][:subscriptions] << "client:#{@settings[:client][:name]}"
138
+ @settings[:client][:subscriptions].uniq!
139
+ @indifferent_access = false
140
+ else
141
+ Legion::Logging.warn('unable to apply legion client overrides, reason: client subscriptions is not an array')
142
+ end
143
+ end
144
+
145
+ def load_overrides!
146
+ load_client_overrides if %w[client rspec].include?(legion_service_name)
147
+ end
148
+
149
+ def set_env!
150
+ ENV['LEGION_LOADED_TEMPFILE'] = create_loaded_tempfile!
151
+ end
152
+
153
+ def validate
154
+ validator = Validator.new
155
+ @errors += validator.run(@settings, legion_service_name)
156
+ end
157
+
158
+ private
159
+
160
+ def setting_category(category)
161
+ @settings[category].map do |name, details|
162
+ details.merge(name: name.to_s)
163
+ end
164
+ end
165
+
166
+ def definition_exists?(category, name)
167
+ @settings[category].key?(name.to_sym)
168
+ end
169
+
170
+ def indifferent_hash
171
+ Hash.new do |hash, key|
172
+ hash[key.to_sym] if key.is_a?(String)
173
+ end
174
+ end
175
+
176
+ def with_indifferent_access(hash)
177
+ hash = indifferent_hash.merge(hash)
178
+ hash.each do |key, value|
179
+ hash[key] = with_indifferent_access(value) if value.is_a?(Hash)
180
+ end
181
+ end
182
+
183
+ def indifferent_access!
184
+ @settings = with_indifferent_access(@settings)
185
+ @indifferent_access = true
186
+ end
187
+
188
+ def load_api_env
189
+ return unless ENV['LEGION_API_PORT']
190
+
191
+ @settings[:api] ||= {}
192
+ @settings[:api][:port] = ENV['LEGION_API_PORT'].to_i
193
+ Legion::Logging.warn("using api port environment variable, api: #{@settings[:api]}")
194
+ @indifferent_access = false
195
+ end
196
+
197
+ def read_config_file(file)
198
+ contents = IO.read(file)
199
+ if contents.respond_to?(:force_encoding)
200
+ encoding = ::Encoding::ASCII_8BIT
201
+ contents = contents.force_encoding(encoding)
202
+ contents.sub!("\xEF\xBB\xBF".force_encoding(encoding), '')
203
+ else
204
+ contents.sub!(/^\357\273\277/, '')
205
+ end
206
+ contents.strip
207
+ end
208
+
209
+ def deep_merge(hash_one, hash_two)
210
+ merged = hash_one.dup
211
+ hash_two.each do |key, value|
212
+ merged[key] = if hash_one[key].is_a?(Hash) && value.is_a?(Hash)
213
+ deep_merge(hash_one[key], value)
214
+ elsif hash_one[key].is_a?(Array) && value.is_a?(Array)
215
+ hash_one[key].concat(value).uniq
216
+ else
217
+ value
218
+ end
219
+ end
220
+ merged
221
+ end
222
+
223
+ # rubocop:disable Metrics/AbcSize
224
+ def deep_diff(hash_one, hash_two)
225
+ keys = hash_one.keys.concat(hash_two.keys).uniq
226
+ keys.each_with_object({}) do |key, diff|
227
+ next if hash_one[key] == hash_two[key]
228
+
229
+ diff[key] = if hash_one[key].is_a?(Hash) && hash_two[key].is_a?(Hash)
230
+ deep_diff(hash_one[key], hash_two[key])
231
+ else
232
+ [hash_one[key], hash_two[key]]
233
+ end
234
+ end
235
+ end
236
+ # rubocop:enable Metrics/AbcSize
237
+
238
+ def create_loaded_tempfile!
239
+ dir = ENV['LEGION_LOADED_TEMPFILE_DIR'] || Dir.tmpdir
240
+ file_name = "legion_#{legion_service_name}_loaded_files"
241
+ path = File.join(dir, file_name)
242
+ File.open(path, 'w') do |file|
243
+ file.write(@loaded_files.join(':'))
244
+ end
245
+ path
246
+ end
247
+
248
+ def legion_service_name
249
+ File.basename($PROGRAM_NAME).split('-').last
250
+ end
251
+
252
+ def system_hostname
253
+ Socket.gethostname
254
+ rescue StandardError
255
+ 'unknown'
256
+ end
257
+
258
+ def system_address
259
+ Socket.ip_address_list.find do |address|
260
+ address.ipv4? && !address.ipv4_loopback?
261
+ end.ip_address
262
+ rescue StandardError
263
+ 'unknown'
264
+ end
265
+
266
+ def warning(message, data = {})
267
+ @warnings << {
268
+ message: message
269
+ }.merge(data)
270
+ Legion::Logging.warn(message)
271
+ end
272
+
273
+ def load_error(message, data = {})
274
+ @errors << {
275
+ message: message
276
+ }.merge(data)
277
+ Legion::Logging.error(message)
278
+ raise(Error, message)
279
+ end
280
+ end
281
+ end
282
+ end
@@ -0,0 +1,170 @@
1
+ module Legion
2
+ module Settings
3
+ module Rules
4
+ # Check that a value is a hash.
5
+ #
6
+ # @param value [Object] to check.
7
+ # @return [TrueClass, FalseClass]
8
+ def must_be_a_hash(value)
9
+ value.is_a?(Hash)
10
+ end
11
+ alias is_a_hash? must_be_a_hash
12
+
13
+ # Check that a value is a hash, if set (not nil).
14
+ #
15
+ # @param value [Object] to check.
16
+ # @return [TrueClass, FalseClass]
17
+ def must_be_a_hash_if_set(value)
18
+ value.nil? ? true : must_be_a_hash(value)
19
+ end
20
+
21
+ # Check that a value is an array.
22
+ #
23
+ # @param value [Object] to check.
24
+ # @return [TrueClass, FalseClass]
25
+ def must_be_an_array(value)
26
+ value.is_a?(Array)
27
+ end
28
+ alias is_an_array? must_be_an_array
29
+
30
+ # Check that a value is an array, if set (not nil).
31
+ #
32
+ # @param value [Object] to check.
33
+ # @return [TrueClass, FalseClass]
34
+ def must_be_an_array_if_set(value)
35
+ value.nil? ? true : must_be_an_array(value)
36
+ end
37
+
38
+ # Check that a value is a string.
39
+ #
40
+ # @param value [Object] to check.
41
+ # @return [TrueClass, FalseClass]
42
+ def must_be_a_string(value)
43
+ value.is_a?(String)
44
+ end
45
+ alias is_a_string? must_be_a_string
46
+
47
+ # Check that a value is a string, if set (not nil).
48
+ #
49
+ # @param value [Object] to check.
50
+ # @return [TrueClass, FalseClass]
51
+ def must_be_a_string_if_set(value)
52
+ value.nil? ? true : must_be_a_string(value)
53
+ end
54
+
55
+ # Check that a value is an integer.
56
+ #
57
+ # @param value [Object] to check.
58
+ # @return [TrueClass, FalseClass]
59
+ def must_be_an_integer(value)
60
+ value.is_a?(Integer)
61
+ end
62
+ alias is_an_integer? must_be_an_integer
63
+
64
+ # Check that a value is an integer, if set (not nil).
65
+ #
66
+ # @param value [Object] to check.
67
+ # @return [TrueClass, FalseClass]
68
+ def must_be_an_integer_if_set(value)
69
+ value.nil? ? true : must_be_an_integer(value)
70
+ end
71
+
72
+ # Check that a value is numeric.
73
+ #
74
+ # @param value [Object] to check.
75
+ # @return [TrueClass, FalseClass]
76
+ def must_be_a_numeric(value)
77
+ value.is_a?(Numeric)
78
+ end
79
+
80
+ # Check that a value is numeric, if set (not nil).
81
+ #
82
+ # @param value [Object] to check.
83
+ # @return [TrueClass, FalseClass]
84
+ def must_be_a_numeric_if_set(value)
85
+ value.nil? ? true : must_be_a_numeric(value)
86
+ end
87
+
88
+ # Check that a value matches a regular expression.
89
+ #
90
+ # @param regex [Regexp] pattern to compare with value.
91
+ # @param value [Object] to check if matches pattern.
92
+ # @return [TrueClass, FalseClass]
93
+ def must_match_regex(regex, value)
94
+ (value =~ regex).zero?
95
+ end
96
+
97
+ # Check if a value is boolean.
98
+ #
99
+ # @param value [Object] to check.
100
+ # @return [TrueClass, FalseClass]
101
+ def must_be_boolean(value)
102
+ !value.nil?
103
+ end
104
+
105
+ # Check if a value is boolean, if set (no nil).
106
+ #
107
+ # @param value [Object] to check.
108
+ # @return [TrueClass, FalseClass]
109
+ def must_be_boolean_if_set(value)
110
+ value.nil? ? true : must_be_boolean(value)
111
+ end
112
+
113
+ # Check that value items are all strings and not empty.
114
+ #
115
+ # @param value [Array] with items to check.
116
+ # @param regex [Regexp] to validate string items with.
117
+ # @return [TrueClass, FalseClass]
118
+ def items_must_be_strings(value, regex = nil)
119
+ value.all? do |item|
120
+ item.is_a?(String) && !item.empty? &&
121
+ (regex.nil? || item =~ regex)
122
+ end
123
+ end
124
+
125
+ # Check if either of the values are set (not nil).
126
+ #
127
+ # @param values [Array<Object>] to check if not nil.
128
+ # @return [TrueClass, FalseClass]
129
+ def either_are_set?(*values)
130
+ values.any? do |value|
131
+ !value.nil?
132
+ end
133
+ end
134
+
135
+ # Check if values are valid times (can be parsed).
136
+ #
137
+ # @param values [Array<Object>] to check if valid time.
138
+ # @return [TrueClass, FalseClass]
139
+ def must_be_time(*values)
140
+ values.all? do |value|
141
+ begin
142
+ Time.parse(value)
143
+ rescue StandardError
144
+ false
145
+ end
146
+ end
147
+ end
148
+
149
+ # Check if values are allowed.
150
+ #
151
+ # @param allowed [Array<Object>] allowed values.
152
+ # @param values [Array<Object>] to check if allowed.
153
+ # @return [TrueClass, FalseClass]
154
+ def must_be_either(allowed, *values)
155
+ values.flatten.all? do |value|
156
+ allowed.include?(value)
157
+ end
158
+ end
159
+
160
+ # Check if values are allowed, if set (not nil).
161
+ #
162
+ # @param allowed [Array<Object>] allowed values.
163
+ # @param values [Array<Object>] to check if allowed.
164
+ # @return [TrueClass, FalseClass]
165
+ def must_be_either_if_set(allowed, *values)
166
+ values[0].nil? ? true : must_be_either(allowed, values)
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,80 @@
1
+ require 'legion/settings/rules'
2
+ require 'legion/settings/validators'
3
+ require 'legion/settings/constants'
4
+
5
+ module Legion
6
+ module Settings
7
+ class Validator
8
+ include Rules
9
+ include Validators
10
+
11
+ # @!attribute [r] failures
12
+ # @return [Array] validation failures.
13
+ attr_reader :failures
14
+
15
+ def initialize
16
+ @failures = []
17
+ end
18
+
19
+ # Run the validator.
20
+ #
21
+ # @param settings [Hash] legion settings to validate.
22
+ # @param service [String] legion service to validate for.
23
+ # @return [Array] validation failures.
24
+ def run(settings, service = nil)
25
+ validate_legion(settings[:legion])
26
+ validate_transport(settings[:transport])
27
+ validate_categories(settings)
28
+ case service
29
+ when 'client'
30
+ validate_client(settings[:client])
31
+ when 'api'
32
+ validate_api(settings[:api])
33
+ when 'rspec'
34
+ validate_client(settings[:client])
35
+ validate_api(settings[:api])
36
+ end
37
+ @failures
38
+ end
39
+
40
+ def reset!
41
+ failure_count = @failures.size
42
+ @failures = []
43
+ failure_count
44
+ end
45
+ alias reset reset!
46
+
47
+ private
48
+
49
+ # Validate setting categories: checks, filters, mutators, and
50
+ # handlers.
51
+ #
52
+ # @param settings [Hash] legion settings to validate.
53
+ def validate_categories(settings)
54
+ CATEGORIES.each do |category|
55
+ if is_a_hash?(settings[category])
56
+ validate_method = ('validate_' + category.to_s.chop).to_sym
57
+ settings[category].each do |name, details|
58
+ send(validate_method, details.merge(name: name.to_s))
59
+ end
60
+ else
61
+ invalid(settings[category], "#{category} must be a hash")
62
+ end
63
+ end
64
+ end
65
+
66
+ # Record an invalid object with a message.
67
+ #
68
+ # @param object [Object] invalid object.
69
+ # @param message [String] message explaining why the object is
70
+ # invalid.
71
+ # @return [Array] current validation failures.
72
+ def invalid(object, message)
73
+ @failures << {
74
+ object: object,
75
+ message: message
76
+ }
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,9 @@
1
+ require 'legion/settings/validators/legion'
2
+
3
+ module Legion
4
+ module Settings
5
+ module Validators
6
+ include Legion
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,37 @@
1
+ module Legion
2
+ module Settings
3
+ module Validators
4
+ module Legion
5
+ # Validate Legion spawn.
6
+ # Validates: limit
7
+ #
8
+ # @param legion [Hash] legion definition.
9
+ def validate_legion_spawn(legion)
10
+ spawn = legion[:spawn]
11
+ if is_a_hash?(spawn)
12
+ if is_an_integer?(spawn[:limit])
13
+ (spawn[:limit]).positive? ||
14
+ invalid(legion, 'legion spawn limit must be greater than 0')
15
+ else
16
+ invalid(legion, 'legion spawn limit must be an integer')
17
+ end
18
+ else
19
+ invalid(legion, 'legion spawn must be a hash')
20
+ end
21
+ end
22
+
23
+ # Validate a Legion definition.
24
+ # Validates: spawn
25
+ #
26
+ # @param legion [Hash] legion definition.
27
+ def validate_legion(legion)
28
+ if is_a_hash?(legion)
29
+ validate_legion_spawn(legion)
30
+ else
31
+ invalid(legion, 'legion must be a hash')
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,5 @@
1
+ module Legion
2
+ module Settings
3
+ VERSION = '0.1.0'.freeze
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,161 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: legion-settings
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Esity
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-12-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: codecov
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
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.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec_junit_formatter
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: legion-json
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.1'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.1'
97
+ - !ruby/object:Gem::Dependency
98
+ name: legion-logging
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.1'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.1'
111
+ description: Based on Sensu's implementation of settings
112
+ email:
113
+ - matthewdiverson@gmail.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".circleci/config.yml"
119
+ - ".gitignore"
120
+ - ".rubocop.yml"
121
+ - Gemfile
122
+ - LICENSE.txt
123
+ - README.md
124
+ - Rakefile
125
+ - bin/console
126
+ - bin/setup
127
+ - bitbucket-pipelines.yml
128
+ - legion-settings.gemspec
129
+ - lib/legion/settings.rb
130
+ - lib/legion/settings/constants.rb
131
+ - lib/legion/settings/loader.rb
132
+ - lib/legion/settings/rules.rb
133
+ - lib/legion/settings/validator.rb
134
+ - lib/legion/settings/validators.rb
135
+ - lib/legion/settings/validators/legion.rb
136
+ - lib/legion/settings/version.rb
137
+ homepage: https://bitbucket.org/whonodes/legion-settings
138
+ licenses:
139
+ - MIT
140
+ metadata: {}
141
+ post_install_message:
142
+ rdoc_options: []
143
+ require_paths:
144
+ - lib
145
+ required_ruby_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ required_rubygems_version: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: '0'
155
+ requirements: []
156
+ rubyforge_project:
157
+ rubygems_version: 2.6.14
158
+ signing_key:
159
+ specification_version: 4
160
+ summary: Used to load the json settings files
161
+ test_files: []