prefab-cloud-ruby 0.11.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 22d564bcc76424b3308623b4d2e27a4acaf4217c285bcca02542291d8cc15827
4
- data.tar.gz: c097169d379d9f477a66d20fc378f693173de044baecad08059263fd239257e5
3
+ metadata.gz: 2525930a7f8c2e2924db43504b7dfb6d32e60647bbc359b8a85af8ae3c9f2db0
4
+ data.tar.gz: 583f5dc901866eaf206f7f693a95bec47b7ea04c54f3d56275a04bbf0a7bb75f
5
5
  SHA512:
6
- metadata.gz: cdf6ca3b1b28bf83caa629193b21e2d26e4d22d64ee4cd30b7a88fdce623adc7f3feb3605df7107cdca00e7823709f9eeac2a68176db1d10b6616196d2bcb580
7
- data.tar.gz: c61b171a2be217c016fad1cc0a1ce9faed159c6f894065db4202ec200ec1f8ac22caabb880fae0f358fcced0930ce49d4e273f800a0fb72c39c6d6f19cc59d07
6
+ metadata.gz: 6c4ff539c75a2d2cfc5e5d6c3ac7bbab494489386d9a1c66ec97af47ab11d46e723a86df862ab8f86a06b09e6ce93d93425f991656cc473395ccf7e2e5fa4da5
7
+ data.tar.gz: 1fe296a9c44484d2d8cc4a185929aaef80358fdee8f3bd83d47152933aa6f684fcf995c3f18bae6feb0389370620e9557d2d37f00d657cc72ef43fdd3b55e37e
data/Gemfile.lock CHANGED
@@ -6,7 +6,7 @@ GEM
6
6
  i18n (>= 0.7, < 2)
7
7
  minitest (~> 5.1)
8
8
  tzinfo (~> 1.1)
9
- addressable (2.7.0)
9
+ addressable (2.8.0)
10
10
  public_suffix (>= 2.0.2, < 5.0)
11
11
  builder (3.2.4)
12
12
  concurrent-ruby (1.1.8)
@@ -26,7 +26,7 @@ GEM
26
26
  ffi-compiler (1.0.1)
27
27
  ffi (>= 1.0.0)
28
28
  rake
29
- git (1.8.1)
29
+ git (1.11.0)
30
30
  rchardet (~> 1.8)
31
31
  github_api (0.19.0)
32
32
  addressable (~> 2.4)
@@ -75,13 +75,13 @@ GEM
75
75
  llhttp-ffi (0.3.1)
76
76
  ffi-compiler (~> 1.0)
77
77
  rake (~> 13.0)
78
- mini_portile2 (2.7.1)
78
+ mini_portile2 (2.8.0)
79
79
  minitest (5.14.4)
80
80
  multi_json (1.15.0)
81
81
  multi_xml (0.6.0)
82
82
  multipart-post (2.1.1)
83
- nokogiri (1.13.1)
84
- mini_portile2 (~> 2.7.0)
83
+ nokogiri (1.13.6)
84
+ mini_portile2 (~> 2.8.0)
85
85
  racc (~> 1.4)
86
86
  oauth2 (1.4.7)
87
87
  faraday (>= 0.8, < 2.0)
data/README.md CHANGED
@@ -43,6 +43,15 @@ on_worker_boot do
43
43
  end
44
44
  ```
45
45
 
46
+ ## Logging & Debugging
47
+ In classpath or ~/.prefab.overrides.config.yaml set
48
+ ```log_level.prefab: debug```
49
+
50
+ To debug issues before this config file has been read, set env var
51
+ ```
52
+ PREFAB_LOG_CLIENT_BOOTSTRAP_LOG_LEVEL = debug
53
+ ```
54
+
46
55
  ## Contributing to prefab-cloud-ruby
47
56
 
48
57
  * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.11.0
1
+ 0.12.0
data/lib/prefab/client.rb CHANGED
@@ -1,46 +1,38 @@
1
1
  module Prefab
2
- class Client
3
2
 
3
+ class Client
4
4
  MAX_SLEEP_SEC = 10
5
5
  BASE_SLEEP_SEC = 0.5
6
- DEFAULT_LOG_FORMATTER = proc {|severity, datetime, progname, msg|
7
- "#{severity.ljust(5)} #{datetime}: #{progname} #{msg}\n"
8
- }
9
-
10
-
11
- attr_reader :project_id, :shared_cache, :stats, :namespace, :interceptor, :api_key, :prefab_api_url
12
-
13
- def initialize(api_key: ENV['PREFAB_API_KEY'],
14
- logdev: nil,
15
- stats: nil, # receives increment("prefab.limitcheck", {:tags=>["policy_group:page_view", "pass:true"]})
16
- shared_cache: nil, # Something that quacks like Rails.cache ideally memcached
17
- local: false,
18
- namespace: "",
19
- log_formatter: DEFAULT_LOG_FORMATTER
20
- )
21
- raise "No API key. Set PREFAB_API_KEY env var" if api_key.nil? || api_key.empty?
22
- raise "PREFAB_API_KEY format invalid. Expecting 123-development-yourapikey-SDK" unless api_key.count("-") == 3
23
- @logdev = (logdev || $stdout)
24
- @log_formatter = log_formatter
25
- @local = local
26
- @stats = (stats || NoopStats.new)
27
- @shared_cache = (shared_cache || NoopCache.new)
28
- @api_key = api_key
29
- @project_id = api_key.split("-")[0].to_i # unvalidated, but that's ok. APIs only listen to the actual passwd
30
- @namespace = namespace
31
- @interceptor = Prefab::AuthInterceptor.new(api_key)
6
+
7
+ attr_reader :project_id, :shared_cache, :stats, :namespace, :interceptor, :api_key, :prefab_api_url, :options
8
+
9
+ def initialize(options = Prefab::Options.new)
10
+ @options = options
11
+ @shared_cache = @options.shared_cache
12
+ @stats = @options.stats
13
+ @namespace = @options.namespace
32
14
  @stubs = {}
33
- @prefab_api_url = ENV["PREFAB_API_URL"] || 'https://api.prefab.cloud'
34
- @prefab_grpc_url = ENV["PREFAB_GRPC_URL"] || 'grpc.prefab.cloud:443'
35
- log_internal Logger::INFO, "Prefab Connecting to: #{@prefab_api_url} and #{@prefab_grpc_url} Secure: #{http_secure?}"
36
- at_exit do
37
- channel.destroy
15
+
16
+ if @options.local_only?
17
+ @project_id = 0
18
+ log_internal Logger::INFO, "Prefab Running in Local Mode"
19
+ else
20
+ @api_key = @options.api_key
21
+ raise "No API key. Set PREFAB_API_KEY env var or use PREFAB_DATASOURCES=LOCAL_ONLY" if @api_key.nil? || @api_key.empty?
22
+ raise "PREFAB_API_KEY format invalid. Expecting 123-development-yourapikey-SDK" unless @api_key.count("-") == 3
23
+ @project_id = @api_key.split("-")[0].to_i # unvalidated, but that's ok. APIs only listen to the actual passwd
24
+ @interceptor = Prefab::AuthInterceptor.new(@api_key)
25
+ @prefab_api_url = @options.prefab_api_url
26
+ @prefab_grpc_url = @options.prefab_grpc_url
27
+ log_internal Logger::INFO, "Prefab Connecting to: #{@prefab_api_url} and #{@prefab_grpc_url} Secure: #{http_secure?}"
28
+ at_exit do
29
+ channel.destroy
30
+ end
38
31
  end
39
32
  end
40
33
 
41
34
  def channel
42
35
  credentials = http_secure? ? creds : :this_channel_is_insecure
43
- log_internal Logger::DEBUG, "GRPC Channel #{@prefab_grpc_url} #{credentials}"
44
36
  @_channel ||= GRPC::Core::Channel.new(@prefab_grpc_url, nil, credentials)
45
37
  end
46
38
 
@@ -57,11 +49,11 @@ module Prefab
57
49
  end
58
50
 
59
51
  def log
60
- @logger_client ||= Prefab::LoggerClient.new(@logdev, formatter: @log_formatter)
52
+ @logger_client ||= Prefab::LoggerClient.new(@options.logdev, formatter: @options.log_formatter)
61
53
  end
62
54
 
63
- def log_internal(level, msg)
64
- log.log_internal msg, "prefab", nil, level
55
+ def log_internal(level, msg, path = "prefab")
56
+ log.log_internal msg, path, nil, level
65
57
  end
66
58
 
67
59
  def request(service, method, req_options: {}, params: {})
@@ -122,7 +114,7 @@ module Prefab
122
114
  Dir["#{OpenSSL::X509::DEFAULT_CERT_DIR}/*.pem"].each do |cert|
123
115
  ssl_certs << File.open(cert).read
124
116
  end
125
- if OpenSSL::X509::DEFAULT_CERT_FILE && File.exists?(OpenSSL::X509::DEFAULT_CERT_FILE)
117
+ if OpenSSL::X509::DEFAULT_CERT_FILE && File.exist?(OpenSSL::X509::DEFAULT_CERT_FILE)
126
118
  ssl_certs << File.open(OpenSSL::X509::DEFAULT_CERT_FILE).read
127
119
  end
128
120
  ssl_certs
@@ -1,41 +1,47 @@
1
1
  module Prefab
2
2
  class ConfigClient
3
+ include Prefab::ConfigHelper
4
+
3
5
  RECONNECT_WAIT = 5
4
6
  DEFAULT_CHECKPOINT_FREQ_SEC = 60
5
7
  DEFAULT_S3CF_BUCKET = 'http://d2j4ed6ti5snnd.cloudfront.net'
8
+ SSE_READ_TIMEOUT = 300
6
9
 
7
10
  def initialize(base_client, timeout)
8
11
  @base_client = base_client
12
+ @options = base_client.options
9
13
  @base_client.log_internal Logger::DEBUG, "Initialize ConfigClient"
10
14
  @timeout = timeout
11
- @initialization_lock = Concurrent::ReadWriteLock.new
15
+
16
+ @stream_lock = Concurrent::ReadWriteLock.new
12
17
 
13
18
  @checkpoint_freq_secs = DEFAULT_CHECKPOINT_FREQ_SEC
14
19
 
15
20
  @config_loader = Prefab::ConfigLoader.new(@base_client)
16
21
  @config_resolver = Prefab::ConfigResolver.new(@base_client, @config_loader)
17
22
 
23
+ @initialization_lock = Concurrent::ReadWriteLock.new
18
24
  @base_client.log_internal Logger::DEBUG, "Initialize ConfigClient: AcquireWriteLock"
19
25
  @initialization_lock.acquire_write_lock
20
26
  @base_client.log_internal Logger::DEBUG, "Initialize ConfigClient: AcquiredWriteLock"
27
+ @initialized_future = Concurrent::Future.execute { @initialization_lock.acquire_read_lock }
21
28
 
22
29
  @cancellable_interceptor = Prefab::CancellableInterceptor.new(@base_client)
23
30
 
24
31
  @s3_cloud_front = ENV["PREFAB_S3CF_BUCKET"] || DEFAULT_S3CF_BUCKET
25
32
 
26
- load_checkpoint
27
- start_checkpointing_thread
33
+ if @options.local_only?
34
+ finish_init!(:local_only)
35
+ else
36
+ load_checkpoint
37
+ start_checkpointing_thread
38
+ start_streaming
39
+ end
28
40
  end
29
41
 
30
42
  def start_streaming
31
- @streaming = true
32
- # start_grpc_streaming_connection_thread(@config_loader.highwater_mark)
33
- start_sse_streaming_connection_thread(@config_loader.highwater_mark)
34
- end
35
-
36
- def get(key)
37
- @initialization_lock.with_read_lock do
38
- @config_resolver.get(key)
43
+ @stream_lock.with_write_lock do
44
+ start_sse_streaming_connection_thread(@config_loader.highwater_mark) if @streaming_thread.nil?
39
45
  end
40
46
  end
41
47
 
@@ -48,7 +54,7 @@ module Prefab
48
54
 
49
55
  @base_client.request Prefab::ConfigService, :upsert, req_options: { timeout: @timeout }, params: upsert_req
50
56
  @base_client.stats.increment("prefab.config.upsert")
51
- @config_loader.set(config_delta)
57
+ @config_loader.set(config_delta, :upsert)
52
58
  @config_loader.rm(previous_key) if previous_key&.present?
53
59
  @config_resolver.update
54
60
  end
@@ -67,14 +73,32 @@ module Prefab
67
73
  rows: [Prefab::ConfigRow.new(value: config_value)])
68
74
  end
69
75
 
76
+ def get(key)
77
+ config = _get(key)
78
+ config ? value_of(config[:value]) : nil
79
+ end
80
+
70
81
  def get_config_obj(key)
71
- @initialization_lock.with_read_lock do
72
- @config_resolver.get_config(key)
73
- end
82
+ config = _get(key)
83
+ config ? config[:config] : nil
74
84
  end
75
85
 
76
86
  private
77
87
 
88
+ def _get(key)
89
+ # wait timeout sec for the initalization to be complete
90
+ @initialized_future.value(@options.initialization_timeout_sec)
91
+ if @initialized_future.incomplete?
92
+ if @options.on_init_failure == Prefab::Options::ON_INITIALIZATION_FAILURE::RETURN
93
+ @base_client.log_internal Logger::WARN, "Couldn't Initialize In #{@options.initialization_timeout_sec}. Key #{key}. Returning what we have"
94
+ @initialization_lock.release_write_lock
95
+ else
96
+ raise "Prefab Couldn't Initialize In #{@options.initialization_timeout_sec} 2 timeout. Key #{key}. "
97
+ end
98
+ end
99
+ @config_resolver._get(key)
100
+ end
101
+
78
102
  def stub
79
103
  @_stub = Prefab::ConfigService::Stub.new(nil,
80
104
  nil,
@@ -82,56 +106,93 @@ module Prefab
82
106
  interceptors: [@base_client.interceptor, @cancellable_interceptor])
83
107
  end
84
108
 
85
- # Bootstrap out of the cache
86
- # returns the high-watermark of what was in the cache
109
+ # try API first, if not, fallback to s3
87
110
  def load_checkpoint
88
- success = load_checkpoint_from_config
111
+ success = load_checkpoint_api_cdn
89
112
 
90
- if !success
91
- @base_client.log_internal Logger::INFO, "Fallback to S3"
92
- load_checkpoint_from_s3
113
+ if success
114
+ return
115
+ else
116
+ @base_client.log_internal Logger::INFO, "LoadCheckpoint: Fallback to GRPC API"
93
117
  end
94
118
 
95
- rescue => e
96
- @base_client.log_internal Logger::WARN, "Unexpected problem loading checkpoint #{e}"
97
- end
119
+ success = load_checkpoint_from_grpc_api
98
120
 
99
- def load_checkpoint_from_config
100
- @base_client.log_internal Logger::DEBUG, "Load Checkpoint From Config"
121
+ if success
122
+ return
123
+ else
124
+ @base_client.log_internal Logger::INFO, "LoadCheckpoint: Fallback to S3"
125
+ end
126
+
127
+ success = load_checkpoint_from_s3
101
128
 
129
+ if !success
130
+ @base_client.log_internal Logger::WARN, "No success loading checkpoints"
131
+ end
132
+ end
133
+
134
+ def load_checkpoint_from_grpc_api
102
135
  config_req = Prefab::ConfigServicePointer.new(start_at_id: @config_loader.highwater_mark)
103
136
 
104
137
  resp = stub.get_all_config(config_req)
105
- @base_client.log_internal Logger::DEBUG, "Got Response #{resp}"
106
- load_configs(resp, :api)
107
- @config_resolver.update
108
- finish_init!(:api)
138
+ load_configs(resp, :remote_api_grpc)
109
139
  true
140
+ rescue GRPC::Unauthenticated
141
+ @base_client.log_internal Logger::WARN, "Unauthenticated"
110
142
  rescue => e
111
- @base_client.log_internal Logger::WARN, "Unexpected problem loading checkpoint #{e}"
143
+ puts e.class
144
+ @base_client.log_internal Logger::WARN, "Unexpected grpc_api problem loading checkpoint #{e}"
112
145
  false
113
146
  end
114
147
 
148
+ def load_checkpoint_api_cdn
149
+ key_hash = Murmur3.murmur3_32(@base_client.api_key)
150
+ url = "#{@options.url_for_api_cdn}/api/v1/config/#{@base_client.project_id}/#{key_hash}/0"
151
+ conn = if Faraday::VERSION[0].to_i >= 2
152
+ Faraday.new(url) do |conn|
153
+ conn.request :authorization, :basic, @base_client.project_id, @base_client.api_key
154
+ end
155
+ else
156
+ Faraday.new(url) do |conn|
157
+ conn.request :basic_auth, @base_client.project_id, @base_client.api_key
158
+ end
159
+ end
160
+ load_url(conn, :remote_cdn_api)
161
+ end
162
+
115
163
  def load_checkpoint_from_s3
116
164
  url = "#{@s3_cloud_front}/#{@base_client.api_key.gsub("|", "/")}"
117
- resp = Faraday.get url
165
+ load_url(Faraday.new(url), :remote_s3)
166
+ end
167
+
168
+ def load_url(conn, source)
169
+ resp = conn.get('')
118
170
  if resp.status == 200
119
171
  configs = Prefab::Configs.decode(resp.body)
120
- load_configs(configs, :s3)
172
+ load_configs(configs, source)
173
+ true
121
174
  else
122
- @base_client.log_internal Logger::INFO, "No S3 checkpoint. Response #{resp.status} Plan may not support this."
175
+ @base_client.log_internal Logger::INFO, "Checkpoint #{source} failed to load. Response #{resp.status}"
176
+ false
123
177
  end
178
+ rescue => e
179
+ @base_client.log_internal Logger::WARN, "Unexpected #{source} problem loading checkpoint #{e} #{conn}"
180
+ false
124
181
  end
125
182
 
126
183
  def load_configs(configs, source)
127
184
  project_env_id = configs.config_service_pointer.project_env_id
128
185
  @config_resolver.project_env_id = project_env_id
186
+ starting_highwater_mark = @config_loader.highwater_mark
129
187
 
130
- @base_client.log_internal Logger::INFO, "Prefab Initializing in project: #{@base_client.project_id} environment: #{project_env_id} and namespace: '#{@namespace}'"
131
188
  configs.configs.each do |config|
132
- @config_loader.set(config)
189
+ @config_loader.set(config, source)
190
+ end
191
+ if @config_loader.highwater_mark > starting_highwater_mark
192
+ @base_client.log_internal Logger::INFO, "Found new checkpoint with highwater id #{@config_loader.highwater_mark} from #{source} in project #{@base_client.project_id} environment: #{project_env_id} and namespace: '#{@namespace}'"
193
+ else
194
+ @base_client.log_internal Logger::DEBUG, "Checkpoint with highwater id #{@config_loader.highwater_mark} from #{source}. No changes.", "prefab.config_client.load_configs"
133
195
  end
134
- @base_client.log_internal Logger::INFO, "Found checkpoint with highwater id #{@config_loader.highwater_mark} from #{source}"
135
196
  @base_client.stats.increment("prefab.config.checkpoint.load")
136
197
  @config_resolver.update
137
198
  finish_init!(source)
@@ -139,6 +200,7 @@ module Prefab
139
200
 
140
201
  # A thread that checks for a checkpoint
141
202
  def start_checkpointing_thread
203
+
142
204
  Thread.new do
143
205
  loop do
144
206
  begin
@@ -158,72 +220,32 @@ module Prefab
158
220
 
159
221
  def finish_init!(source)
160
222
  if @initialization_lock.write_locked?
161
- @base_client.log_internal Logger::DEBUG, "Unlocked Config via #{source}"
223
+ @base_client.log_internal Logger::INFO, "Unlocked Config via #{source}"
162
224
  @initialization_lock.release_write_lock
163
225
  @base_client.log.set_config_client(self)
226
+ @base_client.log_internal Logger::INFO, to_s
164
227
  end
165
228
  end
166
229
 
167
-
168
230
  def start_sse_streaming_connection_thread(start_at_id)
169
231
  auth = "#{@base_client.project_id}:#{@base_client.api_key}"
170
-
171
232
  auth_string = Base64.strict_encode64(auth)
172
233
  headers = {
173
234
  "x-prefab-start-at-id": start_at_id,
174
235
  "Authorization": "Basic #{auth_string}",
175
236
  }
176
237
  url = "#{@base_client.prefab_api_url}/api/v1/sse/config"
177
- @base_client.log_internal Logger::INFO, "SSE Streaming Connect to #{url}"
178
- SSE::Client.new(url, headers: headers) do |client|
238
+ @base_client.log_internal Logger::INFO, "SSE Streaming Connect to #{url} start_at #{start_at_id}"
239
+ @streaming_thread = SSE::Client.new(url,
240
+ headers: headers,
241
+ read_timeout: SSE_READ_TIMEOUT,
242
+ logger: Prefab::InternalLogger.new("prefab.config.sse", @base_client.log)) do |client|
179
243
  client.on_event do |event|
180
244
  configs = Prefab::Configs.decode(Base64.decode64(event.data))
181
- @base_client.log_internal Logger::INFO, "SSE received configs."
182
- @base_client.log_internal Logger::DEBUG, "SSE received configs: #{configs}"
183
- configs.configs.each do |config|
184
- @config_loader.set(config)
185
- end
186
- @config_resolver.update
187
- finish_init!(:streaming)
245
+ load_configs(configs, :sse)
188
246
  end
189
247
  end
190
248
  end
191
-
192
- # Setup a streaming connection to the API
193
- # Save new config values into the loader
194
- def start_grpc_streaming_connection_thread(start_at_id)
195
- config_req = Prefab::ConfigServicePointer.new(start_at_id: start_at_id)
196
- @base_client.log_internal Logger::DEBUG, "start api connection thread #{start_at_id}"
197
- @base_client.stats.increment("prefab.config.api.start")
198
-
199
- @api_connection_thread = Thread.new do
200
- at_exit do
201
- @streaming = false
202
- @cancellable_interceptor.cancel
203
- end
204
-
205
- while @streaming do
206
- begin
207
- resp = stub.get_config(config_req)
208
- resp.each do |r|
209
- r.configs.each do |config|
210
- @config_loader.set(config)
211
- end
212
- @config_resolver.update
213
- finish_init!(:streaming)
214
- end
215
- rescue => e
216
- if @streaming
217
- level = e.code == 1 ? Logger::DEBUG : Logger::INFO
218
- @base_client.log_internal level, ("config client encountered #{e.message} pausing #{RECONNECT_WAIT}")
219
- reset
220
- sleep(RECONNECT_WAIT)
221
- end
222
- end
223
- end
224
- end
225
-
226
- end
227
249
  end
228
250
  end
229
251
 
@@ -16,5 +16,13 @@ module Prefab
16
16
  config_value.segment
17
17
  end
18
18
  end
19
+
20
+ def value_of_variant(feature_flag_variant)
21
+ return feature_flag_variant.string if feature_flag_variant.has_string?
22
+ return feature_flag_variant.int if feature_flag_variant.has_int?
23
+ return feature_flag_variant.double if feature_flag_variant.has_double?
24
+ return feature_flag_variant.bool if feature_flag_variant.has_bool?
25
+ return nil
26
+ end
19
27
  end
20
28
  end
@@ -5,6 +5,7 @@ module Prefab
5
5
 
6
6
  def initialize(base_client)
7
7
  @base_client = base_client
8
+ @prefab_options = base_client.options
8
9
  @highwater_mark = 0
9
10
  @classpath_config = load_classpath_config
10
11
  @local_overrides = load_local_overrides
@@ -20,16 +21,19 @@ module Prefab
20
21
  rtn
21
22
  end
22
23
 
23
- def set(config)
24
+ def set(config, source)
24
25
  # don't overwrite newer values
25
- if @api_config[config.key] && @api_config[config.key].id > config.id
26
+ if @api_config[config.key] && @api_config[config.key][:config].id >= config.id
26
27
  return
27
28
  end
28
29
 
29
30
  if config.rows.empty?
30
31
  @api_config.delete(config.key)
31
32
  else
32
- @api_config[config.key] = config
33
+ if @api_config[config.key]
34
+ @base_client.log_internal Logger::DEBUG, "Replace #{config.key} with value from #{source} #{ @api_config[config.key][:config].id} -> #{config.id}"
35
+ end
36
+ @api_config[config.key] = { source: source, config: config }
33
37
  end
34
38
  @highwater_mark = [config.id, @highwater_mark].max
35
39
  end
@@ -41,7 +45,7 @@ module Prefab
41
45
  def get_api_deltas
42
46
  configs = Prefab::Configs.new
43
47
  @api_config.each_value do |config_value|
44
- configs.configs << config_value
48
+ configs.configs << config_value[:config]
45
49
  end
46
50
  configs
47
51
  end
@@ -49,12 +53,12 @@ module Prefab
49
53
  private
50
54
 
51
55
  def load_classpath_config
52
- classpath_dir = ENV['PREFAB_CONFIG_CLASSPATH_DIR'] || "."
56
+ classpath_dir = @prefab_options.prefab_config_classpath_dir
53
57
  load_glob(File.join(classpath_dir, ".prefab*config.yaml"))
54
58
  end
55
59
 
56
60
  def load_local_overrides
57
- override_dir = ENV['PREFAB_CONFIG_OVERRIDE_DIR'] || Dir.home
61
+ override_dir = @prefab_options.prefab_config_override_dir
58
62
  load_glob(File.join(override_dir, ".prefab*config.yaml"))
59
63
  end
60
64
 
@@ -63,9 +67,26 @@ module Prefab
63
67
  Dir.glob(glob).each do |file|
64
68
  yaml = load(file)
65
69
  yaml.each do |k, v|
66
- rtn[k] = Prefab::Config.new(key: k, rows: [
67
- Prefab::ConfigRow.new(value: Prefab::ConfigValue.new(value_from(v)))
68
- ])
70
+ if v.class == Hash
71
+ v.each do |env_k, env_v|
72
+ if k == @prefab_options.defaults_env
73
+ rtn[env_k] = { source: file,
74
+ match: k,
75
+ config: Prefab::Config.new(key: env_k, rows: [
76
+ Prefab::ConfigRow.new(value: Prefab::ConfigValue.new(value_from(env_v)))
77
+ ]) }
78
+ else
79
+ next
80
+ end
81
+ end
82
+ else
83
+ rtn[k] = { source: file,
84
+ match: "default",
85
+ config: Prefab::Config.new(key: k, rows: [
86
+ Prefab::ConfigRow.new(value: Prefab::ConfigValue.new(value_from(v)))
87
+ ]) }
88
+
89
+ end
69
90
  end
70
91
  end
71
92
  rtn
@@ -8,22 +8,27 @@ module Prefab
8
8
  def initialize(base_client, config_loader)
9
9
  @lock = Concurrent::ReadWriteLock.new
10
10
  @local_store = {}
11
- @namespace = base_client.namespace
11
+ @namespace = base_client.options.namespace
12
12
  @config_loader = config_loader
13
13
  @project_env_id = 0
14
14
  make_local
15
15
  end
16
16
 
17
17
  def to_s
18
- str = ""
18
+ str = "\n"
19
19
  @lock.with_read_lock do
20
20
  @local_store.each do |k, v|
21
+ elements = [k.slice(0..49).ljust(50)]
21
22
  if v.nil?
22
- str<< "|#{k}| tombstone\n"
23
+ elements << "tombstone"
23
24
  else
24
25
  value = v[:value]
25
- str << "|#{k}| from #{v[:match]} |#{value_of(value)}|#{value_of(value).class}\n"
26
+ elements << value_of(value).to_s.slice(0..34).ljust(35)
27
+ elements << value_of(value).class.to_s.slice(0..6).ljust(7)
28
+ elements << "Match: #{v[:match]}".slice(0..29).ljust(30)
29
+ elements << "Source: #{v[:source]}"
26
30
  end
31
+ str << elements.join(" | ") << "\n"
27
32
  end
28
33
  end
29
34
  str
@@ -39,12 +44,14 @@ module Prefab
39
44
  config ? config[:config] : nil
40
45
  end
41
46
 
42
- def update
43
- make_local
47
+ def _get(key)
48
+ @lock.with_read_lock do
49
+ @local_store[key]
50
+ end
44
51
  end
45
52
 
46
- def export_api_deltas
47
- @config_loader.get_api_deltas
53
+ def update
54
+ make_local
48
55
  end
49
56
 
50
57
  private
@@ -64,23 +71,26 @@ module Prefab
64
71
 
65
72
  def make_local
66
73
  store = {}
67
- @config_loader.calc_config.each do |key, config|
74
+ @config_loader.calc_config.each do |key, config_resolver_obj|
75
+ config = config_resolver_obj[:config]
68
76
  sortable = config.rows.map do |row|
69
77
  if row.project_env_id != 0
70
78
  if row.project_env_id == @project_env_id
71
79
  if !row.namespace.empty?
72
80
  (starts_with, count) = starts_with_ns?(row.namespace, @namespace)
73
81
  # rubocop:disable BlockNesting
74
- { sortable: 2 + count, match: row.namespace, value: row.value, config: config} if starts_with
82
+ { sortable: 2 + count, match: "nm:#{row.namespace}", value: row.value, config: config} if starts_with
75
83
  else
76
- { sortable: 1, match: row.project_env_id, value: row.value, config: config}
84
+ { sortable: 1, match: "env:#{row.project_env_id}", value: row.value, config: config}
77
85
  end
78
86
  end
79
87
  else
80
- { sortable: 0, match: "default", value: row.value, config: config}
88
+ match = config_resolver_obj[:match] || "default"
89
+ { sortable: 0, match: match, value: row.value, config: config}
81
90
  end
82
91
  end.compact
83
92
  to_store = sortable.sort_by { |h| h[:sortable] }.last
93
+ to_store[:source] = config_resolver_obj[:source]
84
94
  store[key] = to_store
85
95
  end
86
96
 
@@ -88,11 +98,5 @@ module Prefab
88
98
  @local_store = store
89
99
  end
90
100
  end
91
-
92
- def _get(property)
93
- @lock.with_read_lock do
94
- @local_store[property]
95
- end
96
- end
97
101
  end
98
102
  end