service_skeleton 0.0.0.44.g75d07d7 → 0.0.0.48.g4a40599
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/README.md +259 -144
- data/lib/service_skeleton.rb +20 -186
- data/lib/service_skeleton/config.rb +40 -22
- data/lib/service_skeleton/config_class.rb +16 -0
- data/lib/service_skeleton/config_variable.rb +1 -1
- data/lib/service_skeleton/config_variable/yaml_file.rb +42 -0
- data/lib/service_skeleton/config_variables.rb +28 -23
- data/lib/service_skeleton/error.rb +3 -3
- data/lib/service_skeleton/generator.rb +165 -0
- data/lib/service_skeleton/logging_helpers.rb +3 -3
- data/lib/service_skeleton/metric_method_name.rb +9 -0
- data/lib/service_skeleton/metrics_methods.rb +26 -13
- data/lib/service_skeleton/runner.rb +46 -0
- data/lib/service_skeleton/service_name.rb +20 -0
- data/lib/service_skeleton/signal_manager.rb +202 -0
- data/lib/service_skeleton/signals_methods.rb +15 -0
- data/lib/service_skeleton/ultravisor_children.rb +17 -0
- data/lib/service_skeleton/ultravisor_loggerstash.rb +11 -0
- data/service_skeleton.gemspec +6 -7
- metadata +57 -15
- data/lib/service_skeleton/background_worker.rb +0 -96
- data/lib/service_skeleton/signal_handler.rb +0 -197
data/lib/service_skeleton.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "service_skeleton/
|
3
|
+
require_relative "service_skeleton/config_class"
|
4
4
|
require_relative "service_skeleton/config_variables"
|
5
|
+
require_relative "service_skeleton/generator"
|
5
6
|
require_relative "service_skeleton/logging_helpers"
|
6
7
|
require_relative "service_skeleton/metrics_methods"
|
7
|
-
require_relative "service_skeleton/
|
8
|
+
require_relative "service_skeleton/service_name"
|
9
|
+
require_relative "service_skeleton/signals_methods"
|
10
|
+
require_relative "service_skeleton/ultravisor_children"
|
8
11
|
|
9
12
|
require "frankenstein/ruby_gc_metrics"
|
10
13
|
require "frankenstein/ruby_vm_metrics"
|
@@ -13,195 +16,26 @@ require "frankenstein/server"
|
|
13
16
|
require "prometheus/client/registry"
|
14
17
|
require "sigdump"
|
15
18
|
|
16
|
-
|
17
|
-
extend ServiceSkeleton::ConfigVariables
|
18
|
-
|
19
|
+
module ServiceSkeleton
|
19
20
|
include ServiceSkeleton::LoggingHelpers
|
21
|
+
extend ServiceSkeleton::Generator
|
20
22
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
service_name_from_class(self)
|
23
|
+
def self.included(mod)
|
24
|
+
mod.extend ServiceSkeleton::ServiceName
|
25
|
+
mod.extend ServiceSkeleton::ConfigVariables
|
26
|
+
mod.extend ServiceSkeleton::ConfigClass
|
27
|
+
mod.extend ServiceSkeleton::MetricsMethods
|
28
|
+
mod.extend ServiceSkeleton::SignalsMethods
|
29
|
+
mod.extend ServiceSkeleton::UltravisorChildren
|
29
30
|
end
|
30
31
|
|
31
32
|
attr_reader :config, :metrics, :logger
|
32
33
|
|
33
|
-
def initialize(
|
34
|
-
@
|
35
|
-
@config
|
36
|
-
@logger
|
37
|
-
@op_mutex = Mutex.new
|
38
|
-
|
39
|
-
initialize_metrics
|
40
|
-
initialize_signals
|
41
|
-
end
|
42
|
-
|
43
|
-
def start
|
44
|
-
@op_mutex.synchronize { @thread = Thread.current }
|
45
|
-
|
46
|
-
begin
|
47
|
-
logger.info(logloc) { "Starting service #{service_name}" }
|
48
|
-
logger.info(logloc) { (["Environment:"] + config.env.map { |k, v| "#{k}=#{v.inspect}" }).join("\n ") }
|
49
|
-
|
50
|
-
start_metrics_server
|
51
|
-
start_signal_handler
|
52
|
-
run
|
53
|
-
rescue ServiceSkeleton::Terminate
|
54
|
-
# This one is OK
|
55
|
-
rescue ServiceSkeleton::Error::InheritanceContractError
|
56
|
-
# We want this one to be fatal
|
57
|
-
raise
|
58
|
-
rescue StandardError => ex
|
59
|
-
log_exception(ex)
|
60
|
-
end
|
61
|
-
|
62
|
-
@thread = nil
|
63
|
-
end
|
64
|
-
|
65
|
-
def stop(force = false)
|
66
|
-
if force
|
67
|
-
#:nocov:
|
68
|
-
@op_mutex.synchronize do
|
69
|
-
if @thread
|
70
|
-
@thread.raise(ServiceSkeleton::Terminate)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
#:nocov:
|
74
|
-
else
|
75
|
-
shutdown
|
76
|
-
end
|
77
|
-
|
78
|
-
if @metrics_server
|
79
|
-
@metrics_server.shutdown
|
80
|
-
@metrics_server = nil
|
81
|
-
end
|
82
|
-
|
83
|
-
@signal_handler.stop!
|
84
|
-
end
|
85
|
-
|
86
|
-
def service_name
|
87
|
-
self.class.service_name
|
88
|
-
end
|
89
|
-
|
90
|
-
def registered_variables
|
91
|
-
self.class.registered_variables
|
92
|
-
end
|
93
|
-
|
94
|
-
def hook_signal(spec, &blk)
|
95
|
-
@signal_handler.hook_signal(spec, &blk)
|
96
|
-
end
|
97
|
-
|
98
|
-
private
|
99
|
-
|
100
|
-
def self.service_name_from_class(klass)
|
101
|
-
klass.to_s
|
102
|
-
.gsub("::", "_")
|
103
|
-
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
104
|
-
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
105
|
-
.downcase
|
106
|
-
.gsub(/[^a-zA-Z0-9_]/, "_")
|
107
|
-
end
|
108
|
-
|
109
|
-
def run
|
110
|
-
raise ServiceSkeleton::Error::InheritanceContractError, "ServiceSkeleton#run method not overridden"
|
111
|
-
end
|
112
|
-
|
113
|
-
def shutdown
|
114
|
-
#:nocov:
|
115
|
-
@op_mutex.synchronize do
|
116
|
-
if @thread
|
117
|
-
@thread.raise(ServiceSkeleton::Terminate)
|
118
|
-
@thread.join
|
119
|
-
@thread = nil
|
120
|
-
end
|
121
|
-
end
|
122
|
-
#:nocov:
|
123
|
-
end
|
124
|
-
|
125
|
-
def initialize_metrics
|
126
|
-
@metrics = Prometheus::Client::Registry.new
|
127
|
-
|
128
|
-
Frankenstein::RubyGCMetrics.register(@metrics)
|
129
|
-
Frankenstein::RubyVMMetrics.register(@metrics)
|
130
|
-
Frankenstein::ProcessMetrics.register(@metrics)
|
131
|
-
|
132
|
-
@metrics.singleton_class.prepend(ServiceSkeleton::MetricsMethods)
|
133
|
-
@metrics.service = self
|
134
|
-
end
|
135
|
-
|
136
|
-
def start_metrics_server
|
137
|
-
if config.metrics_port
|
138
|
-
logger.info(logloc) { "Starting metrics server on port #{config.metrics_port}" }
|
139
|
-
|
140
|
-
@metrics_server = Frankenstein::Server.new(
|
141
|
-
port: config.metrics_port,
|
142
|
-
logger: logger,
|
143
|
-
metrics_prefix: :metrics_server,
|
144
|
-
registry: @metrics,
|
145
|
-
)
|
146
|
-
@metrics_server.run
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
def initialize_signals
|
151
|
-
metrics.counter(:"#{self.service_name}_signals_handled_total", "How many of each type of signal have been handled")
|
152
|
-
@signal_handler = ServiceSkeleton::SignalHandler.new(logger: logger, service: self, signal_counter: metrics.signals_handled_total)
|
153
|
-
|
154
|
-
@signal_handler.hook_signal("USR1") do
|
155
|
-
logger.level -= 1 unless logger.level == Logger::DEBUG
|
156
|
-
logger.info($0) { "Received SIGUSR1; log level is now #{Logger::SEV_LABEL[logger.level]}." }
|
157
|
-
end
|
158
|
-
|
159
|
-
@signal_handler.hook_signal("USR2") do
|
160
|
-
logger.level += 1 unless logger.level == Logger::ERROR
|
161
|
-
logger.info($0) { "Received SIGUSR2; log level is now #{Logger::SEV_LABEL[logger.level]}." }
|
162
|
-
end
|
163
|
-
|
164
|
-
@signal_handler.hook_signal("HUP") do
|
165
|
-
logger.reopen
|
166
|
-
logger.info($0) { "Received SIGHUP; log file handle reopened" }
|
167
|
-
end
|
168
|
-
|
169
|
-
@signal_handler.hook_signal("QUIT") do
|
170
|
-
Sigdump.dump("+")
|
171
|
-
end
|
172
|
-
|
173
|
-
@signal_handler.hook_signal("INT") do
|
174
|
-
self.stop(!!@terminating)
|
175
|
-
@terminating = true
|
176
|
-
end
|
177
|
-
|
178
|
-
@signal_handler.hook_signal("TERM") do
|
179
|
-
self.stop(!!@terminating)
|
180
|
-
@terminating = true
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
def start_signal_handler
|
185
|
-
@signal_handler.start!
|
186
|
-
end
|
187
|
-
|
188
|
-
@registered_variables = [
|
189
|
-
{ name: :SERVICE_SKELETON_LOG_LEVEL, class: ConfigVariable::String, opts: { default: "INFO" } },
|
190
|
-
{ name: :SERVICE_SKELETON_LOG_ENABLE_TIMESTAMPS, class: ConfigVariable::Boolean, opts: { default: false } },
|
191
|
-
{ name: :SERVICE_SKELETON_LOG_FILE, class: ConfigVariable::String, opts: { default: nil } },
|
192
|
-
{ name: :SERVICE_SKELETON_LOG_MAX_FILE_SIZE, class: ConfigVariable::Integer, opts: { default: 1048576, range: 0..Float::INFINITY } },
|
193
|
-
{ name: :SERVICE_SKELETON_LOG_MAX_FILES, class: ConfigVariable::Integer, opts: { default: 3, range: 0..Float::INFINITY } },
|
194
|
-
{ name: :SERVICE_SKELETON_LOGSTASH_SERVER, class: ConfigVariable::String, opts: { default: nil } },
|
195
|
-
{ name: :SERVICE_SKELETON_METRICS_PORT, class: ConfigVariable::Integer, opts: { default: nil, range: 1..65535 } },
|
196
|
-
]
|
197
|
-
|
198
|
-
def self.inherited(subclass)
|
199
|
-
subclass.string(:"#{subclass.service_name.upcase}_LOG_LEVEL", default: "INFO")
|
200
|
-
subclass.boolean(:"#{subclass.service_name.upcase}_LOG_ENABLE_TIMESTAMPS", default: false)
|
201
|
-
subclass.string(:"#{subclass.service_name.upcase}_LOG_FILE", default: nil)
|
202
|
-
subclass.integer(:"#{subclass.service_name.upcase}_LOG_MAX_FILE_SIZE", default: 1048576, range: 0..Float::INFINITY)
|
203
|
-
subclass.integer(:"#{subclass.service_name.upcase}_LOG_MAX_FILES", default: 3, range: 1..Float::INFINITY)
|
204
|
-
subclass.string(:"#{subclass.service_name.upcase}_LOGSTASH_SERVER", default: "")
|
205
|
-
subclass.integer(:"#{subclass.service_name.upcase}_METRICS_PORT", default: nil, range: 1..65535)
|
34
|
+
def initialize(*_, metrics:, config:)
|
35
|
+
@metrics = metrics
|
36
|
+
@config = config
|
37
|
+
@logger = @config.logger
|
206
38
|
end
|
207
39
|
end
|
40
|
+
|
41
|
+
require_relative "service_skeleton/runner"
|
@@ -6,18 +6,19 @@ require_relative "./filtering_logger"
|
|
6
6
|
|
7
7
|
require "loggerstash"
|
8
8
|
|
9
|
-
|
9
|
+
module ServiceSkeleton
|
10
10
|
class Config
|
11
|
-
attr_reader :logger, :env
|
11
|
+
attr_reader :logger, :env, :service_name
|
12
12
|
|
13
|
-
def initialize(env,
|
14
|
-
@
|
13
|
+
def initialize(env, service_name, variables)
|
14
|
+
@service_name = service_name
|
15
15
|
|
16
|
-
# Parsing
|
17
|
-
#
|
16
|
+
# Parsing variables will redact the environment, so we want to take a
|
17
|
+
# private unredacted copy before that happens for #[] lookup in the
|
18
|
+
# future.
|
18
19
|
@env = env.to_hash.dup.freeze
|
19
20
|
|
20
|
-
|
21
|
+
parse_variables(internal_variables + variables, env)
|
21
22
|
|
22
23
|
# Sadly, we can't setup the logger until we know *how* to setup the
|
23
24
|
# logger, which requires parsing config variables
|
@@ -25,17 +26,17 @@ class ServiceSkeleton
|
|
25
26
|
end
|
26
27
|
|
27
28
|
def [](k)
|
28
|
-
@env[k]
|
29
|
+
@env[k].dup
|
29
30
|
end
|
30
31
|
|
31
32
|
private
|
32
33
|
|
33
|
-
def
|
34
|
-
|
34
|
+
def parse_variables(variables, env)
|
35
|
+
variables.map do |var|
|
35
36
|
var[:class].new(var[:name], env, **var[:opts])
|
36
37
|
end.each do |var|
|
37
38
|
val = var.value
|
38
|
-
method_name = var.method_name(@
|
39
|
+
method_name = var.method_name(@service_name).to_sym
|
39
40
|
|
40
41
|
define_singleton_method(method_name) do
|
41
42
|
val
|
@@ -65,30 +66,35 @@ class ServiceSkeleton
|
|
65
66
|
|
66
67
|
@logger = Logger.new(log_file || $stderr, shift_age, shift_size)
|
67
68
|
|
68
|
-
if self.logstash_server && !self.logstash_server.empty?
|
69
|
-
loggerstash = Loggerstash.new(logstash_server: logstash_server, logger: @logger)
|
70
|
-
loggerstash.metrics_registry = @svc.metrics
|
71
|
-
loggerstash.attach(@logger)
|
72
|
-
end
|
73
|
-
|
74
|
-
thread_id_map = {}
|
75
69
|
if Thread.main
|
76
|
-
|
70
|
+
Thread.main[:thread_map_number] = 0
|
77
71
|
else
|
78
72
|
#:nocov:
|
79
|
-
|
73
|
+
Thread.current[:thread_map_number] = 0
|
80
74
|
#:nocov:
|
81
75
|
end
|
82
76
|
|
77
|
+
thread_map_mutex = Mutex.new
|
78
|
+
|
83
79
|
@logger.formatter = ->(s, t, p, m) do
|
84
|
-
th_n =
|
80
|
+
th_n = if Thread.current.name
|
81
|
+
#:nocov:
|
82
|
+
Thread.current.name
|
83
|
+
#:nocov:
|
84
|
+
else
|
85
|
+
thread_map_mutex.synchronize do
|
86
|
+
Thread.current[:thread_map_number] ||= begin
|
87
|
+
Thread.list.select { |th| th[:thread_map_number] }.length
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
85
91
|
|
86
92
|
ts = log_enable_timestamps ? "#{t.utc.strftime("%FT%T.%NZ")} " : ""
|
87
93
|
"#{ts}#{$$}##{th_n} #{s[0]} [#{p}] #{m}\n"
|
88
94
|
end
|
89
95
|
|
90
96
|
@logger.filters = []
|
91
|
-
@env.fetch("#{@
|
97
|
+
@env.fetch("#{@service_name.upcase}_LOG_LEVEL", "INFO").split(/\s*,\s*/).each do |spec|
|
92
98
|
if spec.index("=")
|
93
99
|
# "Your developers were so preoccupied with whether or not they
|
94
100
|
# could, they didn't stop to think if they should."
|
@@ -111,5 +117,17 @@ class ServiceSkeleton
|
|
111
117
|
end
|
112
118
|
end
|
113
119
|
end
|
120
|
+
|
121
|
+
def internal_variables
|
122
|
+
[
|
123
|
+
{ name: "#{@service_name.upcase}_LOG_LEVEL", class: ConfigVariable::String, opts: { default: "INFO" } },
|
124
|
+
{ name: "#{@service_name.upcase}_LOG_ENABLE_TIMESTAMPS", class: ConfigVariable::Boolean, opts: { default: false } },
|
125
|
+
{ name: "#{@service_name.upcase}_LOG_FILE", class: ConfigVariable::String, opts: { default: nil } },
|
126
|
+
{ name: "#{@service_name.upcase}_LOG_MAX_FILE_SIZE", class: ConfigVariable::Integer, opts: { default: 1048576, range: 0..Float::INFINITY } },
|
127
|
+
{ name: "#{@service_name.upcase}_LOG_MAX_FILES", class: ConfigVariable::Integer, opts: { default: 3, range: 1..Float::INFINITY } },
|
128
|
+
{ name: "#{@service_name.upcase}_LOGSTASH_SERVER", class: ConfigVariable::String, opts: { default: "" } },
|
129
|
+
{ name: "#{@service_name.upcase}_METRICS_PORT", class: ConfigVariable::Integer, opts: { default: nil, range: 1..65535 } },
|
130
|
+
]
|
131
|
+
end
|
114
132
|
end
|
115
133
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ServiceSkeleton
|
4
|
+
module ConfigClass
|
5
|
+
Undefined = Module.new
|
6
|
+
private_constant :Undefined
|
7
|
+
|
8
|
+
def config_class(klass = Undefined)
|
9
|
+
unless klass == Undefined
|
10
|
+
@config_class = klass
|
11
|
+
end
|
12
|
+
|
13
|
+
@config_class
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "yaml"
|
4
|
+
|
5
|
+
require "service_skeleton/config_variable"
|
6
|
+
|
7
|
+
class ServiceSkeleton::ConfigVariable::YamlFile < ServiceSkeleton::ConfigVariable
|
8
|
+
def redact!(env)
|
9
|
+
if env.has_key?(@name.to_s)
|
10
|
+
if File.world_readable?(env[@name.to_s])
|
11
|
+
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
12
|
+
"Sensitive file #{env[@name.to_s]} is world-readable!"
|
13
|
+
end
|
14
|
+
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def pluck_value(env)
|
22
|
+
maybe_default(env) do
|
23
|
+
begin
|
24
|
+
val = YAML.safe_load(File.read(env[@name.to_s]))
|
25
|
+
if @opts[:klass]
|
26
|
+
val = @opts[:klass].new(val)
|
27
|
+
end
|
28
|
+
|
29
|
+
val
|
30
|
+
rescue Errno::ENOENT
|
31
|
+
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
32
|
+
"YAML file #{env[@name.to_s]} does not exist"
|
33
|
+
rescue Errno::EPERM
|
34
|
+
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
35
|
+
"Do not have permission to read YAML file #{env[@name.to_s]}"
|
36
|
+
rescue Psych::SyntaxError => ex
|
37
|
+
raise ServiceSkeleton::Error::InvalidEnvironmentError,
|
38
|
+
"Invalid YAML syntax: #{ex.message}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -4,71 +4,76 @@ require_relative "./error"
|
|
4
4
|
|
5
5
|
require "service_skeleton/config_variable"
|
6
6
|
|
7
|
-
|
7
|
+
module ServiceSkeleton
|
8
8
|
module ConfigVariables
|
9
|
-
attr_reader :registered_variables
|
10
|
-
|
11
9
|
UNDEFINED = Module.new
|
12
10
|
private_constant :UNDEFINED
|
13
11
|
|
14
|
-
def
|
12
|
+
def registered_variables
|
15
13
|
@registered_variables ||= []
|
14
|
+
end
|
16
15
|
|
16
|
+
def register_variable(name, klass, **opts)
|
17
17
|
if opts[:default] == UNDEFINED
|
18
18
|
opts.delete(:default)
|
19
19
|
end
|
20
20
|
|
21
|
-
|
21
|
+
registered_variables << {
|
22
22
|
name: name,
|
23
23
|
class: klass,
|
24
24
|
opts: opts,
|
25
25
|
}
|
26
26
|
end
|
27
27
|
|
28
|
-
def string(var_name, default: UNDEFINED, sensitive: false, match: nil)
|
29
|
-
register_variable(var_name, ConfigVariable::String, default: default, sensitive: sensitive, match: match)
|
30
|
-
end
|
31
|
-
|
32
28
|
def boolean(var_name, default: UNDEFINED, sensitive: false)
|
33
29
|
register_variable(var_name, ConfigVariable::Boolean, default: default, sensitive: sensitive)
|
34
30
|
end
|
35
31
|
|
36
|
-
def
|
37
|
-
|
32
|
+
def enum(var_name, values:, default: UNDEFINED, sensitive: false)
|
33
|
+
unless values.is_a?(Hash) || values.is_a?(Array)
|
34
|
+
raise ArgumentError,
|
35
|
+
"values option to enum must be a hash or array"
|
36
|
+
end
|
37
|
+
|
38
|
+
register_variable(var_name, ConfigVariable::Enum, default: default, sensitive: sensitive, values: values)
|
38
39
|
end
|
39
40
|
|
40
41
|
def float(var_name, default: UNDEFINED, sensitive: false, range: -Float::INFINITY..Float::INFINITY)
|
41
42
|
register_variable(var_name, ConfigVariable::Float, default: default, sensitive: sensitive, range: range)
|
42
43
|
end
|
43
44
|
|
44
|
-
def
|
45
|
-
register_variable(var_name, ConfigVariable::
|
45
|
+
def integer(var_name, default: UNDEFINED, sensitive: false, range: -Float::INFINITY..Float::INFINITY)
|
46
|
+
register_variable(var_name, ConfigVariable::Integer, default: default, sensitive: sensitive, range: range)
|
46
47
|
end
|
47
48
|
|
48
49
|
def kv_list(var_name, default: UNDEFINED, sensitive: false, key_pattern: /\A#{var_name}_(.*)\z/)
|
49
50
|
register_variable(var_name, ConfigVariable::KVList, default: default, sensitive: sensitive, key_pattern: key_pattern)
|
50
51
|
end
|
51
52
|
|
52
|
-
def
|
53
|
-
|
54
|
-
|
55
|
-
"values option to enum must be a hash or array"
|
56
|
-
end
|
53
|
+
def path_list(var_name, default: UNDEFINED, sensitive: false)
|
54
|
+
register_variable(var_name, ConfigVariable::PathList, default: default, sensitive: sensitive)
|
55
|
+
end
|
57
56
|
|
58
|
-
|
57
|
+
def string(var_name, default: UNDEFINED, sensitive: false, match: nil)
|
58
|
+
register_variable(var_name, ConfigVariable::String, default: default, sensitive: sensitive, match: match)
|
59
59
|
end
|
60
60
|
|
61
61
|
def url(var_name, default: UNDEFINED, sensitive: false)
|
62
62
|
register_variable(var_name, ConfigVariable::URL, default: default, sensitive: sensitive)
|
63
63
|
end
|
64
|
+
|
65
|
+
def yaml_file(var_name, default: UNDEFINED, sensitive: false, klass: nil)
|
66
|
+
register_variable(var_name, ConfigVariable::YamlFile, default: default, sensitive: sensitive, klass: klass)
|
67
|
+
end
|
64
68
|
end
|
65
69
|
end
|
66
70
|
|
67
|
-
require_relative "config_variable/string"
|
68
71
|
require_relative "config_variable/boolean"
|
69
|
-
require_relative "config_variable/
|
72
|
+
require_relative "config_variable/enum"
|
70
73
|
require_relative "config_variable/float"
|
71
|
-
require_relative "config_variable/
|
74
|
+
require_relative "config_variable/integer"
|
72
75
|
require_relative "config_variable/kv_list"
|
73
|
-
require_relative "config_variable/
|
76
|
+
require_relative "config_variable/path_list"
|
77
|
+
require_relative "config_variable/string"
|
74
78
|
require_relative "config_variable/url"
|
79
|
+
require_relative "config_variable/yaml_file"
|