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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 89e508c4ecb8d4e9aaebf054202f87e0ef171578
4
- data.tar.gz: d89449c14673b9a0764c82a4711018dc8db85fce
3
+ metadata.gz: 190533a0da2c8d16b425d2ffa4bde288e19a97da
4
+ data.tar.gz: 69a6e1b680e9525c513e386d427de26f5b6667fd
5
5
  SHA512:
6
- metadata.gz: 3c6cebc9a8e4d0d12331d4d801cbe87866c998c52695c17d5400b8102217f98c117b89bd52dff1eb23be7f09ef8e23827e38f56af4051f28904680d8500e3be0
7
- data.tar.gz: 09bacbedcbbe99b6af2165e6501661267a0e6b7735a3234f9ef3c8c00b92385749c2b2ba9971dbe5a0e7a0c2460f46e4890c3352ff22f8fce0a743d6d9e59ee0
6
+ metadata.gz: 46a2dce89a0a2577808f9bc325766a010b19f58f0fa566c414a9aaa5ba16352e08ae84f25ad0b5d8b55f689b2119ed15156654fa22203527ab5c0f58e2da130f
7
+ data.tar.gz: 0a502681b521e29b05fbdb96b78b5b86821ea35924a05693557566b95ae127ede976bd866efa8e2c7df977b47ff99823aca7720a9de0eaf915c256eb92d6fb6e
data/.gitignore CHANGED
@@ -8,4 +8,5 @@
8
8
  /pkg/
9
9
  /spec/reports/
10
10
  /spec/support/database.yml
11
+ /spec/support/octopus.yml
11
12
  /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
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
- def initialize(router: nil, runner: nil)
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!
@@ -1,3 +1,3 @@
1
1
  module Penthouse
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -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.1.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: []