gorynich 1.1.1.148381 → 1.2.1.184916
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +13 -11
- data/lib/gorynich/fetcher.rb +2 -1
- data/lib/gorynich/fetchers/consul_secure.rb +38 -0
- data/lib/gorynich/head/active_job.rb +6 -0
- data/lib/gorynich/version.rb +1 -1
- data/spec/lib/gorynich/fetchers/consul_secure_spec.rb +45 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: df0c9a5f4faf3db84f91ad8dbdf1c45543ca9be53f63a04ae1bf5fb64049add1
|
4
|
+
data.tar.gz: a93051c9633a546e90a39b47fdc36461448895e764902d0bd120f0bff5eb5f0a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9df0bbce7e717eaf7a72151a5ca9249cabae6d8ddba1122341f0b9d00c4c7bb79e08ec9e88375d39f59d1ec0a49111b09aec0b39abded1f8ec5b4bbbfe2d0bfc
|
7
|
+
data.tar.gz: fa8eff7507bd7aa844092cffdbe669f8a6825fef830bf0eed217223ef610a0b5644bf9f02f7bb7c738da71263130aa0e3e0f29e7c461ab0600db18d74977a7d2
|
data/README.md
CHANGED
@@ -16,7 +16,7 @@
|
|
16
16
|
|
17
17
|
`Gorynich` - это гем для реализации [мультитенантности](https://ru.wikipedia.org/wiki/Мультиарендность) (мультиарендности) в Ruby on Rails приложении. Позволяет обеспечить строгую изоляцию данных в нескольких СУБД, поддерживаемых в ActiveRecord.
|
18
18
|
|
19
|
-
Поскольку мультитенантное приложение тесно связано с разделением данных, которые в свою очередь могут находиться в разных источниках (СУБД, S3, Redis и пр.), а также с их обработкой в разных подсистемах (ActiveJob, ActionCable), мы выбрали название ["Горыныч"](https://ru.wikipedia.org/wiki/Змей_Горыныч), чтобы подчеркнуть ~многоголовость~ многогранность интеграций.
|
19
|
+
Поскольку мультитенантное приложение тесно связано с разделением данных, которые в свою очередь могут находиться в разных источниках (СУБД, S3, Redis и пр.), а также с их обработкой в разных подсистемах (ActiveJob, ActionCable), мы выбрали название ["Горыныч"](https://ru.wikipedia.org/wiki/Змей_Горыныч), чтобы подчеркнуть ~многоголовость~ многогранность интеграций.
|
20
20
|
|
21
21
|
---
|
22
22
|
|
@@ -66,14 +66,14 @@ gem 'gorynich'
|
|
66
66
|
```sh
|
67
67
|
bundle install # для установки гема / gem installation
|
68
68
|
|
69
|
-
rails generate gorynich:install # для добавления шаблонов конфигурации / install configuration templates
|
69
|
+
rails generate gorynich:install # для добавления шаблонов конфигурации / install configuration templates
|
70
70
|
```
|
71
71
|
|
72
72
|
## Что такое тенант? / What tenant is?
|
73
73
|
|
74
74
|
Тенант (в данном случае) - это активное подключение к СУБД, а также доступный в любом месте объект `Gorynich::Current`, в котором находятся параметры текущего тенанта. К нему можно обратиться в любом месте.
|
75
75
|
|
76
|
-
---
|
76
|
+
---
|
77
77
|
|
78
78
|
In this case tenant is an active connection to the DBMS, as well as a `Gorynich::Current` object available anywhere, which contains the parameters of the current tenant. You can refer to it anywhere, for example when sending emails:
|
79
79
|
|
@@ -94,7 +94,7 @@ end
|
|
94
94
|
|
95
95
|
Например, при отправке писем изнутри ActiveJob использование выглядит так:
|
96
96
|
|
97
|
-
---
|
97
|
+
---
|
98
98
|
|
99
99
|
Before request processing [Gorynich::Rack::RackMiddleware](./lib/gorynich/head/rack_middleware.rb) ActiveRecord connection switching to apropriate database. Additional tenant properties available in any part of application through [ActiveSupport::CurrentAttributes](https://api.rubyonrails.org/classes/ActiveSupport/CurrentAttributes.html) as `Gorynich::Current` instance. ActionCable, ActiveJob and other "heads" also uses `Gorynich::Current` to store context and evaluate it later.
|
100
100
|
|
@@ -130,19 +130,21 @@ end
|
|
130
130
|
|
131
131
|
## Использование / Usage
|
132
132
|
|
133
|
-
### Настройка источника данных / Configuration source
|
133
|
+
### Настройка источника данных / Configuration source
|
134
134
|
|
135
|
-
Для использования необходимо в файле `config/application.rb` добавить источник данных. Сейчас доступны
|
135
|
+
Для использования необходимо в файле `config/application.rb` добавить источник данных. Сейчас доступны 3 источника:
|
136
136
|
|
137
137
|
---
|
138
138
|
|
139
|
-
Now you need to select configuration source in `config/application.rb`. Yuo can choose from
|
139
|
+
Now you need to select configuration source in `config/application.rb`. Yuo can choose from 3 source types now:
|
140
140
|
|
141
141
|
|
142
142
|
```ruby
|
143
143
|
Gorynich::Fetchers::File.new(file_path: [FILE_PATH]) # из файла / from file
|
144
144
|
|
145
145
|
Gorynich::Fetchers::Consul.new(storage: [CONSUL_KEY], **options) # из консула / from consul (options - from Dimplomat gem https://github.com/WeAreFarmGeek/diplomat)
|
146
|
+
|
147
|
+
Gorynich::Fetchers::ConsulSecure.new(storage: [CONSUL_KEY], file_path: [FILE_PATH], **options) # из консула с сохранением в файл (при недоступности консула будет читать из файла) / from consul with saving to a file (if unavailable, consul will read from the file) (options - from Dimplomat gem https://github.com/WeAreFarmGeek/diplomat)
|
146
148
|
```
|
147
149
|
|
148
150
|
Пример / Example:
|
@@ -214,7 +216,7 @@ TENANT=tenant rails gc # default tenant name id 'default'
|
|
214
216
|
|
215
217
|
Для создания статичного файла `database.yml` из источника данных (Fetcher) используйте:
|
216
218
|
|
217
|
-
---
|
219
|
+
---
|
218
220
|
|
219
221
|
For static `database.yml` generation from configured source (Fetcher) use:
|
220
222
|
|
@@ -228,7 +230,7 @@ rails gc:db:prepare
|
|
228
230
|
|
229
231
|
Первый, самый простой способ работы, подходящий для локальной разработки, это статическая генерация `database.yml`.
|
230
232
|
|
231
|
-
---
|
233
|
+
---
|
232
234
|
|
233
235
|
First and most simple using of Gorynich handy for local development is static `database.yml` generation.
|
234
236
|
|
@@ -240,7 +242,7 @@ rails gc:db:prepare
|
|
240
242
|
|
241
243
|
2. Полуавтоматический режим / Semi-automated mode
|
242
244
|
|
243
|
-
Второй вариант - это создание конфигурации `database.yml` при старте Rails приложения - данные будут прочитаны из настроенного источника. В этом случае конфигурация СУБД может изменяться только при перезапуске приложения, но остальные настройки, такие как привязка тенантов к доменам и secrets, будут подхватываться "на лету" непосредственно во время работы приложения. Rake-задачи `db:create`, `db:migrate` работают для всех тенантов на момент запуска.
|
245
|
+
Второй вариант - это создание конфигурации `database.yml` при старте Rails приложения - данные будут прочитаны из настроенного источника. В этом случае конфигурация СУБД может изменяться только при перезапуске приложения, но остальные настройки, такие как привязка тенантов к доменам и secrets, будут подхватываться "на лету" непосредственно во время работы приложения. Rake-задачи `db:create`, `db:migrate` работают для всех тенантов на момент запуска.
|
244
246
|
|
245
247
|
---
|
246
248
|
|
@@ -353,7 +355,7 @@ config.telegram_updates_controller.session_store = :redis_cache_store, {
|
|
353
355
|
}
|
354
356
|
```
|
355
357
|
|
356
|
-
### Shrine
|
358
|
+
### Shrine
|
357
359
|
|
358
360
|
```ruby
|
359
361
|
#lib/shrine/plugins/tenant_location.rb
|
data/lib/gorynich/fetcher.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require_relative 'fetchers/file'
|
2
2
|
require_relative 'fetchers/consul'
|
3
|
+
require_relative 'fetchers/consul_secure'
|
3
4
|
|
4
5
|
module Gorynich
|
5
6
|
class Fetcher
|
@@ -32,7 +33,7 @@ module Gorynich
|
|
32
33
|
elsif @fetcher.is_a?(Array)
|
33
34
|
result = {}
|
34
35
|
@fetcher.each do |f|
|
35
|
-
result =
|
36
|
+
result =
|
36
37
|
begin
|
37
38
|
f.fetch
|
38
39
|
rescue ::StandardError
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Gorynich
|
2
|
+
module Fetchers
|
3
|
+
class ConsulSecure
|
4
|
+
attr_reader :storage, :file_path, :consul_opts
|
5
|
+
|
6
|
+
def initialize(storage:, file_path:, **opts)
|
7
|
+
@storage = storage
|
8
|
+
@file_path = file_path
|
9
|
+
@consul_opts = opts
|
10
|
+
end
|
11
|
+
|
12
|
+
def fetch
|
13
|
+
cfg = Consul.new(storage: storage, **consul_opts).fetch
|
14
|
+
return from_file if cfg.empty?
|
15
|
+
|
16
|
+
save_to_file(cfg)
|
17
|
+
|
18
|
+
cfg
|
19
|
+
rescue ::StandardError
|
20
|
+
from_file
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def save_to_file(cfg)
|
26
|
+
envs = ::Dir.glob(::Rails.root.join('config/environments/*.rb').to_s).map { |f| ::File.basename(f, '.rb') }
|
27
|
+
|
28
|
+
::File.open(file_path, 'w') do |f|
|
29
|
+
f << cfg.deep_transform_keys(&:downcase).select { |k, _v| envs.include?(k) }.to_yaml.gsub('---', '')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def from_file
|
34
|
+
File.new(file_path: file_path).fetch
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -16,6 +16,12 @@ module Gorynich
|
|
16
16
|
@current_tenant = job_data.fetch(:tenant)
|
17
17
|
end
|
18
18
|
|
19
|
+
def retry_job(**_options)
|
20
|
+
Gorynich.with(current_tenant, uri: current_uri) do |_current|
|
21
|
+
super
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
19
25
|
around_perform do |job, block|
|
20
26
|
Gorynich.with(
|
21
27
|
job.current_tenant || Gorynich::Current.tenant,
|
data/lib/gorynich/version.rb
CHANGED
@@ -0,0 +1,45 @@
|
|
1
|
+
RSpec.describe Gorynich::Fetchers::ConsulSecure do
|
2
|
+
let(:storage) { Faker::Lorem.word }
|
3
|
+
let(:file_path) { "#{RSPEC_ROOT}/fixtures/fetchers/file_config.yml" }
|
4
|
+
let(:file_like_object) { double("file like object") }
|
5
|
+
|
6
|
+
context '#fetch' do
|
7
|
+
let(:consul_host) { Faker::Internet.url }
|
8
|
+
let(:consul_opts) { { http_addr: consul_host } }
|
9
|
+
|
10
|
+
def consul_request(response, code = 200)
|
11
|
+
stub_request(:get, "#{consul_host}/v1/kv/#{storage}?recurse=true")
|
12
|
+
.to_return(
|
13
|
+
status: code,
|
14
|
+
body: response
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
subject { described_class.new(storage: storage, file_path: file_path, **consul_opts) }
|
19
|
+
|
20
|
+
describe 'when consul return data' do
|
21
|
+
let(:response) { [{ 'Key' => "#{storage}/test_key", 'Value' => Base64.encode64('test') }].to_json }
|
22
|
+
|
23
|
+
before(:each) do
|
24
|
+
consul_request(response)
|
25
|
+
end
|
26
|
+
|
27
|
+
it do
|
28
|
+
allow(File).to receive(:open).with(file_path, 'w').and_return(file_like_object)
|
29
|
+
expect(subject.fetch).to eq({ 'test_key' => 'test' })
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'when http error' do
|
34
|
+
before(:each) do
|
35
|
+
consul_request([], 500)
|
36
|
+
end
|
37
|
+
|
38
|
+
it do
|
39
|
+
result = subject.fetch
|
40
|
+
expect(result.class).to eq(Hash)
|
41
|
+
expect(result).to include('development', 'test')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gorynich
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.1.184916
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Poliev Alexey
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2023-
|
12
|
+
date: 2023-09-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: diplomat
|
@@ -286,6 +286,7 @@ files:
|
|
286
286
|
- lib/gorynich/engine.rb
|
287
287
|
- lib/gorynich/fetcher.rb
|
288
288
|
- lib/gorynich/fetchers/consul.rb
|
289
|
+
- lib/gorynich/fetchers/consul_secure.rb
|
289
290
|
- lib/gorynich/fetchers/file.rb
|
290
291
|
- lib/gorynich/head.rb
|
291
292
|
- lib/gorynich/head/action_cable.rb
|
@@ -358,6 +359,7 @@ files:
|
|
358
359
|
- spec/fixtures/test_database.yml
|
359
360
|
- spec/lib/gorynich/config_spec.rb
|
360
361
|
- spec/lib/gorynich/fetcher_spec.rb
|
362
|
+
- spec/lib/gorynich/fetchers/consul_secure_spec.rb
|
361
363
|
- spec/lib/gorynich/fetchers/consul_spec.rb
|
362
364
|
- spec/lib/gorynich/fetchers/file_spec.rb
|
363
365
|
- spec/lib/gorynich/version_spec.rb
|
@@ -450,6 +452,7 @@ test_files:
|
|
450
452
|
- spec/fixtures/test_database.yml
|
451
453
|
- spec/lib/gorynich/config_spec.rb
|
452
454
|
- spec/lib/gorynich/fetcher_spec.rb
|
455
|
+
- spec/lib/gorynich/fetchers/consul_secure_spec.rb
|
453
456
|
- spec/lib/gorynich/fetchers/consul_spec.rb
|
454
457
|
- spec/lib/gorynich/fetchers/file_spec.rb
|
455
458
|
- spec/lib/gorynich/version_spec.rb
|