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 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: []