penthouse 0.1.0 → 0.2.0
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/.gitignore +1 -0
- data/.rspec +2 -0
- data/README.md +19 -1
- data/lib/penthouse.rb +17 -0
- data/lib/penthouse/configuration.rb +14 -2
- data/lib/penthouse/migrator.rb +39 -0
- data/lib/penthouse/tasks/enhancements.rb +35 -0
- data/lib/penthouse/version.rb +1 -1
- data/lib/tasks/penthouse.rake +94 -0
- metadata +5 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 190533a0da2c8d16b425d2ffa4bde288e19a97da
|
4
|
+
data.tar.gz: 69a6e1b680e9525c513e386d427de26f5b6667fd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 46a2dce89a0a2577808f9bc325766a010b19f58f0fa566c414a9aaa5ba16352e08ae84f25ad0b5d8b55f689b2119ed15156654fa22203527ab5c0f58e2da130f
|
7
|
+
data.tar.gz: 0a502681b521e29b05fbdb96b78b5b86821ea35924a05693557566b95ae127ede976bd866efa8e2c7df977b47ff99823aca7720a9de0eaf915c256eb92d6fb6e
|
data/.gitignore
CHANGED
data/.rspec
ADDED
data/README.md
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
[ ](https://codeship.com/projects/140114) [](https://codeclimate.com/github/ryantownsend/penthouse)
|
2
|
+
|
1
3
|
Penthouse is an alternative to the excellent [Apartment gem](https://github.com/influitive/apartment) – however Penthouse is more of a framework for multi-tenancy than a library, in that it provides less out-of-the-box functionality, but should make for easier customisation.
|
2
4
|
|
3
5
|
## Installation
|
@@ -8,7 +10,7 @@ Add this line to your application's Gemfile:
|
|
8
10
|
gem 'penthouse'
|
9
11
|
```
|
10
12
|
|
11
|
-
## Usage
|
13
|
+
## Basic Usage
|
12
14
|
|
13
15
|
If you're using Rails, you just need to configure an initializer at `config/initializers/penthouse.rb`
|
14
16
|
|
@@ -25,6 +27,10 @@ require 'penthouse/runners/schema_runner'
|
|
25
27
|
Penthouse.configure do |config|
|
26
28
|
config.router = Penthouse::Routers::SubdomainRouter
|
27
29
|
config.runner = Penthouse::Runners::SchemaRunner
|
30
|
+
# enhance migrations to migrate all tenants
|
31
|
+
config.migrate_tenants = true
|
32
|
+
# setup a proc which will return the tenants
|
33
|
+
config.tenant_identifiers = Proc.new { Account.pluck(:tenant_name) }
|
28
34
|
end
|
29
35
|
|
30
36
|
Rails.application.config.middleware.use Penthouse::App
|
@@ -32,6 +38,18 @@ Rails.application.config.middleware.use Penthouse::App
|
|
32
38
|
|
33
39
|
It's advised that if you want to customise these classes, you do so by sub-classing `Penthouse::App`, `Penthouse::Routers::BaseRouter` and/or `Penthouse::Runners::BaseRunner` within this initializer.
|
34
40
|
|
41
|
+
## Octopus (shard) Usage
|
42
|
+
|
43
|
+
If you want to have multiple databases on isolated hardware, you'll need to use the Octopus tenant types. In addition to the above initializer you'll need to configure Octopus:
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
require 'octopus'
|
47
|
+
|
48
|
+
Octopus.setup do |config|
|
49
|
+
config.environments = [Rails.env]
|
50
|
+
end
|
51
|
+
```
|
52
|
+
|
35
53
|
## Dictionary
|
36
54
|
|
37
55
|
* **Router** – this class receives a Rack request object and returns an identifier (just a string or symbol) for the tenant.
|
data/lib/penthouse.rb
CHANGED
@@ -32,6 +32,17 @@ module Penthouse
|
|
32
32
|
self.tenant = default_tenant
|
33
33
|
end
|
34
34
|
|
35
|
+
# Wraps Penthouse.switch and simply executes the block of code for each
|
36
|
+
# tenant within Penthouse.tenant_identifiers
|
37
|
+
# @param default_tenant [String, Symbol] the identifier for the tenant to return to
|
38
|
+
# @param block [Block] the code to execute
|
39
|
+
# @yield [String, Symbol] the identifier for the tenant
|
40
|
+
def each_tenant(default_tenant: tenant, runner: configuration.runner, &block)
|
41
|
+
tenant_identifiers.each do |tenant_identifier|
|
42
|
+
switch(tenant_identifier, runner: runner, &block)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
35
46
|
# Executes the given block of code within a given tenant
|
36
47
|
# @param tenant_identifier [String, Symbol] the identifier for the tenant
|
37
48
|
# @param runner [Penthouse::Runners::BaseRunner] an optional runner to use, defaults to the one configured
|
@@ -57,5 +68,11 @@ module Penthouse
|
|
57
68
|
runner: Runners::BaseRunner
|
58
69
|
)
|
59
70
|
end
|
71
|
+
|
72
|
+
# Returns a array of tenant identifiers based on the configured setting
|
73
|
+
# @return [Array<String, Symbol>] the list of tenant identifiers
|
74
|
+
def tenant_identifiers
|
75
|
+
configuration.tenant_identifiers.call
|
76
|
+
end
|
60
77
|
end
|
61
78
|
end
|
@@ -6,16 +6,28 @@
|
|
6
6
|
# Penthouse.configure do |config|
|
7
7
|
# config.router = Penthouse::Routers::BaseRouter
|
8
8
|
# config.runner = Penthouse::Runners::BaseRunner
|
9
|
+
# config
|
9
10
|
# end
|
10
11
|
#
|
11
12
|
|
12
13
|
module Penthouse
|
13
14
|
class Configuration
|
14
|
-
attr_accessor :router, :runner
|
15
|
+
attr_accessor :router, :runner, :migrate_tenants, :tenant_identifiers
|
15
16
|
|
16
|
-
|
17
|
+
# @param router [Penthouse::Routers::BaseRouter] the default router for your application to use
|
18
|
+
# @param runner [Penthouse::Runners::BaseRunner] the default runner for your application to use
|
19
|
+
# @param migrate_tenants [Boolean] whether you want Penthouse to automatically migrate all tenants
|
20
|
+
# @param tenant_identifiers [Proc] some code which must return an array of tenant identifiers (strings/symbols)
|
21
|
+
def initialize(router: nil, runner: nil, migrate_tenants: false, tenant_identifiers: -> { raise NotImplementedError })
|
17
22
|
self.router = router
|
18
23
|
self.runner = runner
|
24
|
+
self.migrate_tenants = migrate_tenants
|
25
|
+
self.tenant_identifiers = tenant_identifiers
|
26
|
+
end
|
27
|
+
|
28
|
+
# @return [Boolean] whether or not Penthouse should automatically migrate all tenants
|
29
|
+
def migrate_tenants?
|
30
|
+
!!migrate_tenants
|
19
31
|
end
|
20
32
|
end
|
21
33
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# shamelessly copied & adjusted from Apartment
|
2
|
+
# @see https://github.com/influitive/apartment/blob/development/lib/apartment/migrator.rb
|
3
|
+
|
4
|
+
module Penthouse
|
5
|
+
module Migrator
|
6
|
+
|
7
|
+
extend self
|
8
|
+
|
9
|
+
# Migrate to latest version
|
10
|
+
# @param tenant_identifier [String, Symbol] the identifier for the tenant to switch to
|
11
|
+
def migrate(tenant_identifier)
|
12
|
+
Penthouse.switch(tenant_identifier) do
|
13
|
+
version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
|
14
|
+
|
15
|
+
ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths, version) do |migration|
|
16
|
+
ENV["SCOPE"].blank? || (ENV["SCOPE"] == migration.scope)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Migrate up/down to a specific version
|
22
|
+
# @param tenant_identifier [String, Symbol] the identifier for the tenant to switch to
|
23
|
+
# @param version [Integer] the version number to migrate up or down to
|
24
|
+
def run(direction, tenant_identifier, version)
|
25
|
+
Penthouse.switch(tenant_identifier) do
|
26
|
+
ActiveRecord::Migrator.run(direction, ActiveRecord::Migrator.migrations_paths, version)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# rollback latest migration `step` number of times
|
31
|
+
# @param tenant_identifier [String, Symbol] the identifier for the tenant to switch to
|
32
|
+
# @param step [Integer] how many migrations to rollback by
|
33
|
+
def rollback(tenant_identifier, step = 1)
|
34
|
+
Penthouse.switch(tenant_identifier) do
|
35
|
+
ActiveRecord::Migrator.rollback(ActiveRecord::Migrator.migrations_paths, step)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Require this file to append Penthouse rake tasks to ActiveRecord db rake tasks
|
2
|
+
# Enabled by default in the initializer
|
3
|
+
|
4
|
+
# shamelessly copied & adjusted from Apartment
|
5
|
+
# @see https://github.com/influitive/apartment/blob/development/lib/apartment/tasks/enhancements.rb
|
6
|
+
|
7
|
+
module Penthouse
|
8
|
+
class RakeTaskEnhancer
|
9
|
+
TASKS = %w(db:migrate db:rollback db:migrate:up db:migrate:down db:migrate:redo db:seed)
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def enhance!
|
13
|
+
TASKS.each do |name|
|
14
|
+
task = Rake::Task[name]
|
15
|
+
task.enhance do
|
16
|
+
if should_enhance?
|
17
|
+
enhance_task(task)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def should_enhance?
|
24
|
+
Penthouse.configuration.migrate_tenants?
|
25
|
+
end
|
26
|
+
|
27
|
+
def enhance_task(task)
|
28
|
+
Rake::Task[task.name.sub(/db:/, 'penthouse:')].invoke
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
Penthouse::RakeTaskEnhancer.enhance!
|
data/lib/penthouse/version.rb
CHANGED
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'penthouse/migrator'
|
2
|
+
|
3
|
+
penthouse_namespace = namespace :penthouse do
|
4
|
+
|
5
|
+
desc "Migrate all tenants to latest version"
|
6
|
+
task :migrate do
|
7
|
+
warn_if_tenants_empty
|
8
|
+
|
9
|
+
tenant_identifiers.each do |tenant_identifier|
|
10
|
+
begin
|
11
|
+
puts("Migrating #{tenant_identifier} tenant")
|
12
|
+
Penthouse::Migrator.migrate(tenant_identifier)
|
13
|
+
rescue Penthouse::TenantNotFound => e
|
14
|
+
puts e.message
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "Rolls the migration back to the previous version (specify steps w/ STEP=n) across all tenants."
|
20
|
+
task :rollback do
|
21
|
+
warn_if_tenants_empty
|
22
|
+
|
23
|
+
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
|
24
|
+
|
25
|
+
tenant_identifiers.each do |tenant_identifier|
|
26
|
+
begin
|
27
|
+
puts("Rolling back #{tenant_identifier} tenant")
|
28
|
+
Penthouse::Migrator.rollback(tenant_identifier, step)
|
29
|
+
rescue Penthouse::TenantNotFound => e
|
30
|
+
puts e.message
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
namespace :migrate do
|
36
|
+
desc 'Runs the "up" for a given migration VERSION across all tenants.'
|
37
|
+
task :up do
|
38
|
+
warn_if_tenants_empty
|
39
|
+
|
40
|
+
version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
|
41
|
+
raise 'VERSION is required' unless version
|
42
|
+
|
43
|
+
tenant_identifiers.each do |tenant_identifier|
|
44
|
+
begin
|
45
|
+
puts("Migrating #{tenant_identifier} tenant up")
|
46
|
+
Penthouse::Migrator.run(:up, tenant_identifier, version)
|
47
|
+
rescue Penthouse::TenantNotFound => e
|
48
|
+
puts e.message
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
desc 'Runs the "down" for a given migration VERSION across all tenants.'
|
54
|
+
task :down do
|
55
|
+
warn_if_tenants_empty
|
56
|
+
|
57
|
+
version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
|
58
|
+
raise 'VERSION is required' unless version
|
59
|
+
|
60
|
+
tenant_identifiers.each do |tenant_identifier|
|
61
|
+
begin
|
62
|
+
puts("Migrating #{tenant_identifier} tenant down")
|
63
|
+
Penthouse::Migrator.run(:down, tenant_identifier, version)
|
64
|
+
rescue Penthouse::TenantNotFound => e
|
65
|
+
puts e.message
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
desc 'Rolls back the tenant one migration and re-migrate up (options: STEP=x, VERSION=x).'
|
71
|
+
task :redo do
|
72
|
+
if ENV['VERSION']
|
73
|
+
penthouse_namespace['migrate:down'].invoke
|
74
|
+
penthouse_namespace['migrate:up'].invoke
|
75
|
+
else
|
76
|
+
penthouse_namespace['rollback'].invoke
|
77
|
+
penthouse_namespace['migrate'].invoke
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def tenant_identifiers
|
83
|
+
Penthouse.tenant_identifiers
|
84
|
+
end
|
85
|
+
|
86
|
+
def warn_if_tenants_empty
|
87
|
+
if tenant_identifiers.empty?
|
88
|
+
puts <<-WARNING
|
89
|
+
[WARNING] - The list of tenants to migrate appears to be empty. This could mean you've not created any.
|
90
|
+
Note that your tenants currently haven't been migrated. You'll need to run `db:migrate` to rectify this.
|
91
|
+
WARNING
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: penthouse
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Townsend
|
@@ -158,6 +158,7 @@ extensions: []
|
|
158
158
|
extra_rdoc_files: []
|
159
159
|
files:
|
160
160
|
- ".gitignore"
|
161
|
+
- ".rspec"
|
161
162
|
- ".ruby-gemset"
|
162
163
|
- ".ruby-version"
|
163
164
|
- Gemfile
|
@@ -168,6 +169,7 @@ files:
|
|
168
169
|
- lib/penthouse.rb
|
169
170
|
- lib/penthouse/app.rb
|
170
171
|
- lib/penthouse/configuration.rb
|
172
|
+
- lib/penthouse/migrator.rb
|
171
173
|
- lib/penthouse/routers/base_router.rb
|
172
174
|
- lib/penthouse/routers/subdomain_router.rb
|
173
175
|
- lib/penthouse/runners/base_runner.rb
|
@@ -176,11 +178,13 @@ files:
|
|
176
178
|
- lib/penthouse/sidekiq/middleware/client.rb
|
177
179
|
- lib/penthouse/sidekiq/middleware/server.rb
|
178
180
|
- lib/penthouse/sidekiq/railtie.rb
|
181
|
+
- lib/penthouse/tasks/enhancements.rb
|
179
182
|
- lib/penthouse/tenants/base_tenant.rb
|
180
183
|
- lib/penthouse/tenants/octopus_schema_tenant.rb
|
181
184
|
- lib/penthouse/tenants/octopus_shard_tenant.rb
|
182
185
|
- lib/penthouse/tenants/schema_tenant.rb
|
183
186
|
- lib/penthouse/version.rb
|
187
|
+
- lib/tasks/penthouse.rake
|
184
188
|
- penthouse.gemspec
|
185
189
|
homepage: https://github.com/ryantownsend/penthouse
|
186
190
|
licenses: []
|