smplkit 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE +21 -0
- data/README.md +105 -0
- data/lib/smplkit/client.rb +218 -0
- data/lib/smplkit/config/client.rb +238 -0
- data/lib/smplkit/config/helpers.rb +108 -0
- data/lib/smplkit/config/models.rb +192 -0
- data/lib/smplkit/config_resolution.rb +202 -0
- data/lib/smplkit/context.rb +68 -0
- data/lib/smplkit/debug.rb +50 -0
- data/lib/smplkit/errors.rb +114 -0
- data/lib/smplkit/flags/client.rb +480 -0
- data/lib/smplkit/flags/helpers.rb +76 -0
- data/lib/smplkit/flags/models.rb +258 -0
- data/lib/smplkit/flags/types.rb +233 -0
- data/lib/smplkit/generators/install_generator.rb +42 -0
- data/lib/smplkit/helpers.rb +15 -0
- data/lib/smplkit/log_level.rb +57 -0
- data/lib/smplkit/logging/adapters/base.rb +63 -0
- data/lib/smplkit/logging/adapters/semantic_logger_adapter.rb +88 -0
- data/lib/smplkit/logging/adapters/stdlib_logger_adapter.rb +143 -0
- data/lib/smplkit/logging/client.rb +142 -0
- data/lib/smplkit/logging/helpers.rb +69 -0
- data/lib/smplkit/logging/levels.rb +86 -0
- data/lib/smplkit/logging/models.rb +124 -0
- data/lib/smplkit/logging/normalize.rb +16 -0
- data/lib/smplkit/logging/sources.rb +44 -0
- data/lib/smplkit/management/buffer.rb +111 -0
- data/lib/smplkit/management/client.rb +623 -0
- data/lib/smplkit/management/models.rb +133 -0
- data/lib/smplkit/management/types.rb +65 -0
- data/lib/smplkit/metrics.rb +78 -0
- data/lib/smplkit/railtie.rb +48 -0
- data/lib/smplkit/version.rb +5 -0
- data/lib/smplkit/ws.rb +92 -0
- data/lib/smplkit.rb +43 -0
- data/sig/smplkit.rbs +141 -0
- metadata +139 -0
|
@@ -0,0 +1,623 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "faraday"
|
|
4
|
+
require "json"
|
|
5
|
+
require "concurrent"
|
|
6
|
+
|
|
7
|
+
module Smplkit
|
|
8
|
+
# Top-level management client. Owns the HTTP transports + CRUD APIs for
|
|
9
|
+
# every resource on the smplkit platform.
|
|
10
|
+
#
|
|
11
|
+
# Sub-namespaces (mirroring the Python SDK):
|
|
12
|
+
#
|
|
13
|
+
# - +mgmt.contexts.*+
|
|
14
|
+
# - +mgmt.context_types.*+
|
|
15
|
+
# - +mgmt.environments.*+
|
|
16
|
+
# - +mgmt.account_settings.*+
|
|
17
|
+
# - +mgmt.config.*+
|
|
18
|
+
# - +mgmt.flags.*+
|
|
19
|
+
# - +mgmt.loggers.*+
|
|
20
|
+
# - +mgmt.log_groups.*+
|
|
21
|
+
#
|
|
22
|
+
# Constructable both as +Smplkit::ManagementClient.new+ (standalone) and as
|
|
23
|
+
# +Smplkit::Client#manage+ (shared transports).
|
|
24
|
+
class ManagementClient
|
|
25
|
+
attr_reader :contexts, :context_types, :environments, :account_settings,
|
|
26
|
+
:config, :flags, :loggers, :log_groups
|
|
27
|
+
|
|
28
|
+
def self.from_resolved(resolved)
|
|
29
|
+
new(_resolved: resolved)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def initialize(api_key: nil, base_domain: nil, scheme: nil, profile: nil,
|
|
33
|
+
debug: nil, _resolved: nil)
|
|
34
|
+
cfg = _resolved ||
|
|
35
|
+
ConfigResolution.resolve_management_config(
|
|
36
|
+
api_key: api_key, base_domain: base_domain, scheme: scheme,
|
|
37
|
+
profile: profile, debug: debug
|
|
38
|
+
)
|
|
39
|
+
Smplkit.enable_debug if cfg.debug
|
|
40
|
+
|
|
41
|
+
@resolved = cfg
|
|
42
|
+
@app_http = build_http(ConfigResolution.service_url(cfg.scheme, "app", cfg.base_domain), cfg.api_key)
|
|
43
|
+
@config_http = build_http(ConfigResolution.service_url(cfg.scheme, "config", cfg.base_domain), cfg.api_key)
|
|
44
|
+
@flags_http = build_http(ConfigResolution.service_url(cfg.scheme, "flags", cfg.base_domain), cfg.api_key)
|
|
45
|
+
@logging_http = build_http(ConfigResolution.service_url(cfg.scheme, "logging", cfg.base_domain), cfg.api_key)
|
|
46
|
+
|
|
47
|
+
@contexts = ContextsNamespace.new(@app_http)
|
|
48
|
+
@context_types = ContextTypesNamespace.new(@app_http)
|
|
49
|
+
@environments = EnvironmentsNamespace.new(@app_http)
|
|
50
|
+
@account_settings = AccountSettingsNamespace.new(@app_http)
|
|
51
|
+
@config = ConfigNamespace.new(@config_http)
|
|
52
|
+
@flags = FlagsNamespace.new(@flags_http)
|
|
53
|
+
@loggers = LoggersNamespace.new(@logging_http)
|
|
54
|
+
@log_groups = LogGroupsNamespace.new(@logging_http)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def close
|
|
58
|
+
[@app_http, @config_http, @flags_http, @logging_http].each do |conn|
|
|
59
|
+
conn.close if conn.respond_to?(:close)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def _resolved = @resolved
|
|
64
|
+
def _app_http = @app_http
|
|
65
|
+
def _config_http = @config_http
|
|
66
|
+
def _flags_http = @flags_http
|
|
67
|
+
def _logging_http = @logging_http
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
def build_http(base_url, api_key)
|
|
72
|
+
Faraday.new(url: base_url) do |f|
|
|
73
|
+
f.request :authorization, "Bearer", api_key
|
|
74
|
+
f.headers["Content-Type"] = "application/vnd.api+json"
|
|
75
|
+
f.headers["Accept"] = "application/vnd.api+json"
|
|
76
|
+
f.headers["User-Agent"] = "smplkit-ruby-sdk/#{Smplkit::VERSION}"
|
|
77
|
+
f.adapter Faraday.default_adapter
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# ------------------------------------------------------------------
|
|
82
|
+
# Sub-namespaces
|
|
83
|
+
# ------------------------------------------------------------------
|
|
84
|
+
|
|
85
|
+
# Shared HTTP helpers used by every namespace below.
|
|
86
|
+
#
|
|
87
|
+
# All methods are prefixed +http_+ to avoid colliding with the public
|
|
88
|
+
# +get+ / +list+ accessors on each namespace.
|
|
89
|
+
module HttpHelpers
|
|
90
|
+
private
|
|
91
|
+
|
|
92
|
+
def http_get(path)
|
|
93
|
+
response = @http.get(path)
|
|
94
|
+
Errors.raise_for_status(response.status, response.body)
|
|
95
|
+
response.body.to_s.empty? ? {} : JSON.parse(response.body)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def http_list(path)
|
|
99
|
+
body = http_get(path)
|
|
100
|
+
body["data"] || []
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def http_post(path, body)
|
|
104
|
+
response = @http.post(path) do |req|
|
|
105
|
+
req.body = body.is_a?(String) ? body : JSON.generate(body)
|
|
106
|
+
end
|
|
107
|
+
Errors.raise_for_status(response.status, response.body)
|
|
108
|
+
response.body.to_s.empty? ? {} : JSON.parse(response.body)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def http_put(path, body)
|
|
112
|
+
response = @http.put(path) do |req|
|
|
113
|
+
req.body = body.is_a?(String) ? body : JSON.generate(body)
|
|
114
|
+
end
|
|
115
|
+
Errors.raise_for_status(response.status, response.body)
|
|
116
|
+
response.body.to_s.empty? ? {} : JSON.parse(response.body)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def http_delete(path)
|
|
120
|
+
response = @http.delete(path)
|
|
121
|
+
Errors.raise_for_status(response.status, response.body)
|
|
122
|
+
true
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
class ContextsNamespace
|
|
127
|
+
include HttpHelpers
|
|
128
|
+
|
|
129
|
+
def initialize(http)
|
|
130
|
+
@http = http
|
|
131
|
+
@buffer = Management::ContextRegistrationBuffer.new
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def register(contexts)
|
|
135
|
+
return if contexts.nil? || contexts.empty?
|
|
136
|
+
|
|
137
|
+
@buffer.observe(contexts)
|
|
138
|
+
flush if @buffer.pending_count >= Management::CONTEXT_BATCH_FLUSH_SIZE
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def flush
|
|
142
|
+
batch = @buffer.drain
|
|
143
|
+
return if batch.empty?
|
|
144
|
+
|
|
145
|
+
body = { "data" => { "type" => "context_bulk_register", "attributes" => { "contexts" => batch } } }
|
|
146
|
+
http_post("/api/contexts/v1/bulk", body)
|
|
147
|
+
rescue StandardError => e
|
|
148
|
+
Smplkit.debug("registration", "context flush failed: #{e.class}: #{e.message}")
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def list
|
|
152
|
+
list_resp = http_list("/api/contexts/v1")
|
|
153
|
+
list_resp.map { |r| context_from_resource(r) }
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def get(id_or_type, key = nil)
|
|
157
|
+
type, ckey = split_id(id_or_type, key)
|
|
158
|
+
resource = http_get("/api/contexts/v1/#{type}:#{ckey}")
|
|
159
|
+
context_from_resource(resource["data"])
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def delete(id_or_type, key = nil)
|
|
163
|
+
type, ckey = split_id(id_or_type, key)
|
|
164
|
+
http_delete("/api/contexts/v1/#{type}:#{ckey}")
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def _save_context(ctx)
|
|
168
|
+
body = {
|
|
169
|
+
"data" => {
|
|
170
|
+
"type" => "context",
|
|
171
|
+
"id" => ctx.id,
|
|
172
|
+
"attributes" => { "type" => ctx.type, "key" => ctx.key, "attributes" => ctx.attributes }.compact
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
resp = http_put("/api/contexts/v1/#{ctx.id}", body)
|
|
176
|
+
context_from_resource(resp["data"]).tap { |c| c._bind_client(self) }
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
private
|
|
180
|
+
|
|
181
|
+
def split_id(id_or_type, key)
|
|
182
|
+
return [id_or_type, key] if key
|
|
183
|
+
|
|
184
|
+
unless id_or_type.include?(":")
|
|
185
|
+
raise ArgumentError, "context id must be 'type:key' (got #{id_or_type.inspect}); " \
|
|
186
|
+
"alternatively pass type and key as separate args"
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
id_or_type.split(":", 2)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def context_from_resource(resource)
|
|
193
|
+
attrs = resource["attributes"] || {}
|
|
194
|
+
Smplkit::Context.new(
|
|
195
|
+
attrs["type"] || resource["id"].to_s.split(":").first,
|
|
196
|
+
attrs["key"] || resource["id"].to_s.split(":", 2).last,
|
|
197
|
+
attrs["attributes"] || {},
|
|
198
|
+
name: attrs["name"],
|
|
199
|
+
created_at: attrs["created_at"],
|
|
200
|
+
updated_at: attrs["updated_at"]
|
|
201
|
+
)._bind_client(self)
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
class ContextTypesNamespace
|
|
206
|
+
include HttpHelpers
|
|
207
|
+
|
|
208
|
+
def initialize(http)
|
|
209
|
+
@http = http
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def list
|
|
213
|
+
list_resp = http_list("/api/context_types/v1")
|
|
214
|
+
list_resp.map { |r| from_resource(r) }
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def get(key)
|
|
218
|
+
resp = http_get("/api/context_types/v1/#{key}")
|
|
219
|
+
from_resource(resp["data"])
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def delete(key)
|
|
223
|
+
http_delete("/api/context_types/v1/#{key}")
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def new_context_type(key, name: nil, description: nil)
|
|
227
|
+
Management::ContextType.new(self, key: key, name: name, description: description)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def _create_context_type(ct)
|
|
231
|
+
resp = http_post("/api/context_types/v1", body_for(ct))
|
|
232
|
+
from_resource(resp["data"])
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def _update_context_type(ct)
|
|
236
|
+
resp = http_put("/api/context_types/v1/#{ct.key}", body_for(ct))
|
|
237
|
+
from_resource(resp["data"])
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
private
|
|
241
|
+
|
|
242
|
+
def body_for(ct)
|
|
243
|
+
{
|
|
244
|
+
"data" => {
|
|
245
|
+
"type" => "context_type",
|
|
246
|
+
"id" => ct.key,
|
|
247
|
+
"attributes" => { "key" => ct.key, "name" => ct.name, "description" => ct.description }.compact
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def from_resource(resource)
|
|
253
|
+
attrs = resource["attributes"] || {}
|
|
254
|
+
Management::ContextType.new(
|
|
255
|
+
self,
|
|
256
|
+
id: resource["id"], key: attrs["key"] || resource["id"],
|
|
257
|
+
name: attrs["name"], description: attrs["description"],
|
|
258
|
+
created_at: attrs["created_at"], updated_at: attrs["updated_at"]
|
|
259
|
+
)
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
class EnvironmentsNamespace
|
|
264
|
+
include HttpHelpers
|
|
265
|
+
|
|
266
|
+
def initialize(http)
|
|
267
|
+
@http = http
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def list
|
|
271
|
+
list_resp = http_list("/api/environments/v1")
|
|
272
|
+
list_resp.map { |r| from_resource(r) }
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def get(key)
|
|
276
|
+
resp = http_get("/api/environments/v1/#{key}")
|
|
277
|
+
from_resource(resp["data"])
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def delete(key)
|
|
281
|
+
http_delete("/api/environments/v1/#{key}")
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def new(key, name: nil, color: nil,
|
|
285
|
+
classification: Management::EnvironmentClassification::STANDARD,
|
|
286
|
+
description: nil)
|
|
287
|
+
color = Management::Color.new(color) if color.is_a?(String)
|
|
288
|
+
Management::Environment.new(
|
|
289
|
+
self,
|
|
290
|
+
key: key, name: name || Smplkit::Helpers.key_to_display_name(key),
|
|
291
|
+
color: color, classification: classification, description: description
|
|
292
|
+
)
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
def _create_environment(env)
|
|
296
|
+
resp = http_post("/api/environments/v1", body_for(env))
|
|
297
|
+
from_resource(resp["data"])
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
def _update_environment(env)
|
|
301
|
+
resp = http_put("/api/environments/v1/#{env.key}", body_for(env))
|
|
302
|
+
from_resource(resp["data"])
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
private
|
|
306
|
+
|
|
307
|
+
def body_for(env)
|
|
308
|
+
{
|
|
309
|
+
"data" => {
|
|
310
|
+
"type" => "environment",
|
|
311
|
+
"id" => env.key,
|
|
312
|
+
"attributes" => {
|
|
313
|
+
"key" => env.key,
|
|
314
|
+
"name" => env.name,
|
|
315
|
+
"color" => env.color&.hex,
|
|
316
|
+
"classification" => env.classification,
|
|
317
|
+
"description" => env.description
|
|
318
|
+
}.compact
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
def from_resource(resource)
|
|
324
|
+
attrs = resource["attributes"] || {}
|
|
325
|
+
color = attrs["color"] && Management::Color.new(attrs["color"])
|
|
326
|
+
Management::Environment.new(
|
|
327
|
+
self,
|
|
328
|
+
id: resource["id"], key: attrs["key"] || resource["id"],
|
|
329
|
+
name: attrs["name"], color: color,
|
|
330
|
+
classification: attrs["classification"] || Management::EnvironmentClassification::STANDARD,
|
|
331
|
+
description: attrs["description"],
|
|
332
|
+
created_at: attrs["created_at"], updated_at: attrs["updated_at"]
|
|
333
|
+
)
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
class AccountSettingsNamespace
|
|
338
|
+
include HttpHelpers
|
|
339
|
+
|
|
340
|
+
def initialize(http)
|
|
341
|
+
@http = http
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
def get
|
|
345
|
+
resp = http_get("/api/account_settings/v1")
|
|
346
|
+
from_resource(resp["data"])
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
def _update_account_settings(settings)
|
|
350
|
+
resp = http_put("/api/account_settings/v1", body_for(settings))
|
|
351
|
+
from_resource(resp["data"])
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
private
|
|
355
|
+
|
|
356
|
+
def body_for(settings)
|
|
357
|
+
{
|
|
358
|
+
"data" => {
|
|
359
|
+
"type" => "account_settings",
|
|
360
|
+
"attributes" => {
|
|
361
|
+
"environment_order" => settings.environment_order,
|
|
362
|
+
"default_environment" => settings.default_environment
|
|
363
|
+
}.compact
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
def from_resource(resource)
|
|
369
|
+
attrs = resource["attributes"] || {}
|
|
370
|
+
Management::AccountSettings.new(
|
|
371
|
+
self,
|
|
372
|
+
id: resource["id"],
|
|
373
|
+
environment_order: attrs["environment_order"] || [],
|
|
374
|
+
default_environment: attrs["default_environment"],
|
|
375
|
+
updated_at: attrs["updated_at"]
|
|
376
|
+
)
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
class ConfigNamespace
|
|
381
|
+
include HttpHelpers
|
|
382
|
+
|
|
383
|
+
def initialize(http)
|
|
384
|
+
@http = http
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
def list
|
|
388
|
+
list_resp = http_list("/api/configs/v1")
|
|
389
|
+
list_resp.map { |r| Smplkit::Config::Helpers.config_from_json(self, r) }
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
def get(key)
|
|
393
|
+
resp = http_get("/api/configs/v1/#{key}")
|
|
394
|
+
Smplkit::Config::Helpers.config_from_json(self, resp["data"])
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
def delete(key)
|
|
398
|
+
http_delete("/api/configs/v1/#{key}")
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
def new_config(key, name: nil, description: nil, parent: nil)
|
|
402
|
+
Smplkit::Config::Config.new(
|
|
403
|
+
self, key: key, name: name, description: description,
|
|
404
|
+
parent_id: parent.is_a?(Smplkit::Config::Config) ? parent.key : parent
|
|
405
|
+
)
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
def _create_config(config)
|
|
409
|
+
body = Smplkit::Config::Helpers.build_config_request_body(config)
|
|
410
|
+
resp = http_post("/api/configs/v1", body)
|
|
411
|
+
Smplkit::Config::Helpers.config_from_json(self, resp["data"])
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
def _update_config(config)
|
|
415
|
+
body = Smplkit::Config::Helpers.build_config_request_body(config)
|
|
416
|
+
resp = http_put("/api/configs/v1/#{config.key}", body)
|
|
417
|
+
Smplkit::Config::Helpers.config_from_json(self, resp["data"])
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
def fetch_chain(key)
|
|
421
|
+
resp = http_get("/api/configs/v1/#{key}/chain")
|
|
422
|
+
(resp["data"] || []).map { |r| r["attributes"] || {} }
|
|
423
|
+
end
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
class FlagsNamespace
|
|
427
|
+
include HttpHelpers
|
|
428
|
+
|
|
429
|
+
def initialize(http)
|
|
430
|
+
@http = http
|
|
431
|
+
@buffer = Management::FlagRegistrationBuffer.new
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
def register(declaration)
|
|
435
|
+
@buffer.add(declaration)
|
|
436
|
+
flush if @buffer.pending_count >= Management::FLAG_BATCH_FLUSH_SIZE
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
def flush
|
|
440
|
+
batch = @buffer.drain
|
|
441
|
+
return if batch.empty?
|
|
442
|
+
|
|
443
|
+
body = { "data" => { "type" => "flag_bulk_register", "attributes" => { "flags" => batch } } }
|
|
444
|
+
http_post("/api/flags/v1/bulk", body)
|
|
445
|
+
rescue StandardError => e
|
|
446
|
+
Smplkit.debug("registration", "flag flush failed: #{e.class}: #{e.message}")
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
def list
|
|
450
|
+
list_resp = http_list("/api/flags/v1")
|
|
451
|
+
list_resp.map { |r| flag_from_resource(r) }
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
def get(id)
|
|
455
|
+
resp = http_get("/api/flags/v1/#{id}")
|
|
456
|
+
flag_from_resource(resp["data"])
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
def delete(id)
|
|
460
|
+
http_delete("/api/flags/v1/#{id}")
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
def new_boolean_flag(id, default:, name: nil, description: nil, values: nil)
|
|
464
|
+
Smplkit::Flags::BooleanFlag.new(
|
|
465
|
+
self, id: id, name: name || id, type: "BOOLEAN", default: default,
|
|
466
|
+
description: description, values: values
|
|
467
|
+
)
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
def new_string_flag(id, default:, name: nil, description: nil, values: nil)
|
|
471
|
+
Smplkit::Flags::StringFlag.new(
|
|
472
|
+
self, id: id, name: name || id, type: "STRING", default: default,
|
|
473
|
+
description: description, values: values
|
|
474
|
+
)
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
def new_number_flag(id, default:, name: nil, description: nil, values: nil)
|
|
478
|
+
Smplkit::Flags::NumberFlag.new(
|
|
479
|
+
self, id: id, name: name || id, type: "NUMERIC", default: default,
|
|
480
|
+
description: description, values: values
|
|
481
|
+
)
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
def new_json_flag(id, default:, name: nil, description: nil, values: nil)
|
|
485
|
+
Smplkit::Flags::JsonFlag.new(
|
|
486
|
+
self, id: id, name: name || id, type: "JSON", default: default,
|
|
487
|
+
description: description, values: values
|
|
488
|
+
)
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
def _create_flag(flag)
|
|
492
|
+
body = Smplkit::Flags::Helpers.build_flag_request_body(flag)
|
|
493
|
+
resp = http_post("/api/flags/v1", body)
|
|
494
|
+
flag_from_resource(resp["data"])
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
def _update_flag(flag)
|
|
498
|
+
body = Smplkit::Flags::Helpers.build_flag_request_body(flag)
|
|
499
|
+
resp = http_put("/api/flags/v1/#{flag.id}", body)
|
|
500
|
+
flag_from_resource(resp["data"])
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
def fetch_flag(id)
|
|
504
|
+
resp = http_get("/api/flags/v1/#{id}")
|
|
505
|
+
Smplkit::Flags::Helpers.flag_dict_from_json(resp["data"])
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
def list_flags
|
|
509
|
+
body = http_list("/api/flags/v1")
|
|
510
|
+
body.map { |r| Smplkit::Flags::Helpers.flag_dict_from_json(r) }
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
private
|
|
514
|
+
|
|
515
|
+
def flag_from_resource(resource)
|
|
516
|
+
d = Smplkit::Flags::Helpers.flag_dict_from_json(resource)
|
|
517
|
+
klass =
|
|
518
|
+
case d["type"]
|
|
519
|
+
when "BOOLEAN" then Smplkit::Flags::BooleanFlag
|
|
520
|
+
when "STRING" then Smplkit::Flags::StringFlag
|
|
521
|
+
when "NUMERIC" then Smplkit::Flags::NumberFlag
|
|
522
|
+
else Smplkit::Flags::JsonFlag
|
|
523
|
+
end
|
|
524
|
+
klass.new(
|
|
525
|
+
self,
|
|
526
|
+
id: d["id"], name: d["name"], type: d["type"], default: d["default"],
|
|
527
|
+
description: d["description"], values: d["values"], environments: d["environments"],
|
|
528
|
+
created_at: (resource["attributes"] || {})["created_at"],
|
|
529
|
+
updated_at: (resource["attributes"] || {})["updated_at"]
|
|
530
|
+
)
|
|
531
|
+
end
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
class LoggersNamespace
|
|
535
|
+
include HttpHelpers
|
|
536
|
+
|
|
537
|
+
def initialize(http)
|
|
538
|
+
@http = http
|
|
539
|
+
@buffer = Management::LoggerRegistrationBuffer.new
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
def register(source)
|
|
543
|
+
sources = source.is_a?(Array) ? source : [source]
|
|
544
|
+
sources.each { |s| @buffer.add(s) }
|
|
545
|
+
flush if @buffer.pending_count >= Management::LOGGER_BATCH_FLUSH_SIZE
|
|
546
|
+
end
|
|
547
|
+
|
|
548
|
+
def flush
|
|
549
|
+
batch = @buffer.drain
|
|
550
|
+
return if batch.empty?
|
|
551
|
+
|
|
552
|
+
body = { "data" => { "type" => "logger_bulk_register", "attributes" => { "loggers" => batch } } }
|
|
553
|
+
http_post("/api/loggers/v1/bulk", body)
|
|
554
|
+
rescue StandardError => e
|
|
555
|
+
Smplkit.debug("registration", "logger flush failed: #{e.class}: #{e.message}")
|
|
556
|
+
end
|
|
557
|
+
|
|
558
|
+
def list
|
|
559
|
+
list_resp = http_list("/api/loggers/v1")
|
|
560
|
+
list_resp.map { |r| Smplkit::Logging::Helpers.logger_resource_to_model(self, r) }
|
|
561
|
+
end
|
|
562
|
+
|
|
563
|
+
def get(id)
|
|
564
|
+
normalized = Smplkit::Logging::Normalize.normalize_logger_name(id)
|
|
565
|
+
resp = http_get("/api/loggers/v1/#{normalized}")
|
|
566
|
+
Smplkit::Logging::Helpers.logger_resource_to_model(self, resp["data"])
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
def delete(id)
|
|
570
|
+
normalized = Smplkit::Logging::Normalize.normalize_logger_name(id)
|
|
571
|
+
http_delete("/api/loggers/v1/#{normalized}")
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
def _update_logger(logger)
|
|
575
|
+
body = Smplkit::Logging::Helpers.build_logger_body(logger)
|
|
576
|
+
resp = http_put("/api/loggers/v1/#{logger.id || logger.name}", body)
|
|
577
|
+
Smplkit::Logging::Helpers.logger_resource_to_model(self, resp["data"])
|
|
578
|
+
end
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
class LogGroupsNamespace
|
|
582
|
+
include HttpHelpers
|
|
583
|
+
|
|
584
|
+
def initialize(http)
|
|
585
|
+
@http = http
|
|
586
|
+
end
|
|
587
|
+
|
|
588
|
+
def list
|
|
589
|
+
list_resp = http_list("/api/log_groups/v1")
|
|
590
|
+
list_resp.map { |r| Smplkit::Logging::Helpers.log_group_resource_to_model(self, r) }
|
|
591
|
+
end
|
|
592
|
+
|
|
593
|
+
def get(key)
|
|
594
|
+
resp = http_get("/api/log_groups/v1/#{key}")
|
|
595
|
+
Smplkit::Logging::Helpers.log_group_resource_to_model(self, resp["data"])
|
|
596
|
+
end
|
|
597
|
+
|
|
598
|
+
def delete(key)
|
|
599
|
+
http_delete("/api/log_groups/v1/#{key}")
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
def new_log_group(key, name: nil, level: nil, description: nil, parent: nil)
|
|
603
|
+
Smplkit::Logging::SmplLogGroup.new(
|
|
604
|
+
self, key: key, name: name || Smplkit::Helpers.key_to_display_name(key),
|
|
605
|
+
level: level && Smplkit::LogLevel.coerce(level), description: description,
|
|
606
|
+
parent_id: parent.is_a?(Smplkit::Logging::SmplLogGroup) ? parent.key : parent
|
|
607
|
+
)
|
|
608
|
+
end
|
|
609
|
+
|
|
610
|
+
def _create_log_group(group)
|
|
611
|
+
body = Smplkit::Logging::Helpers.build_log_group_body(group)
|
|
612
|
+
resp = http_post("/api/log_groups/v1", body)
|
|
613
|
+
Smplkit::Logging::Helpers.log_group_resource_to_model(self, resp["data"])
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
def _update_log_group(group)
|
|
617
|
+
body = Smplkit::Logging::Helpers.build_log_group_body(group)
|
|
618
|
+
resp = http_put("/api/log_groups/v1/#{group.key}", body)
|
|
619
|
+
Smplkit::Logging::Helpers.log_group_resource_to_model(self, resp["data"])
|
|
620
|
+
end
|
|
621
|
+
end
|
|
622
|
+
end
|
|
623
|
+
end
|