penthouse 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[ ![Codeship Status](https://codeship.com/projects/c6513ab0-cc05-0133-94c6-0666c337ff82/status?branch=master)](https://codeship.com/projects/140114) [![Code Climate](https://codeclimate.com/github/ryantownsend/penthouse/badges/gpa.svg)](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: []
|