Commit b1b3e471f1143b0b8aab231005c896c571ea7de2

Authored by Caio SBA
Committed by Daniela Feitosa
1 parent f2a648b7

Multitenancy documentation and separation

(ActionItem1845)
INSTALL.multitenancy
@@ -11,7 +11,7 @@ organization works with a customized virtual application instance. @@ -11,7 +11,7 @@ organization works with a customized virtual application instance.
11 11
12 Today this feature is available only for PostgreSQL databases. 12 Today this feature is available only for PostgreSQL databases.
13 13
14 -This document assumes that you have a fully PostgresSQL default Noosfero 14 +This document assumes that you have a new fully PostgresSQL default Noosfero
15 installation as explained at the INSTALL file. 15 installation as explained at the INSTALL file.
16 16
17 == Separated data 17 == Separated data
@@ -121,11 +121,6 @@ Run Noosfero init file as root: @@ -121,11 +121,6 @@ Run Noosfero init file as root:
121 It's necessary to run only one instance of ferret_server. Don't worry 121 It's necessary to run only one instance of ferret_server. Don't worry
122 about this, Noosfero initializer had already done this for you. 122 about this, Noosfero initializer had already done this for you.
123 123
124 -Build or rebuild the Ferret index by running the following task just  
125 -for your hosting environment, do this as noosfero user:  
126 -  
127 -$ RAILS_ENV=production rake multitenancy:reindex  
128 -  
129 == Feed updater & Delayed job 124 == Feed updater & Delayed job
130 125
131 Just for your information, a daemon of feed-updater and delayed_job 126 Just for your information, a daemon of feed-updater and delayed_job
@@ -137,3 +132,32 @@ relax. @@ -137,3 +132,32 @@ relax.
137 When running with PostgreSQL, Noosfero uploads stuff to a folder named 132 When running with PostgreSQL, Noosfero uploads stuff to a folder named
138 the same way as the running schema. Inside the upload folder root, for 133 the same way as the running schema. Inside the upload folder root, for
139 example, will be public/image_uploads/env2 and public/image_uploads/env3. 134 example, will be public/image_uploads/env2 and public/image_uploads/env3.
  135 +
  136 +== Adding multitenancy support to an existing Noosfero environment
  137 +
  138 +If you already have a Noosfero environment, you can turn it multitenant
  139 +by following the steps below in addition to the previous steps:
  140 +
  141 +1. Reindex your database
  142 +
  143 +Rebuild the Ferret index by running the following task just
  144 +for your hosting environment, do this as noosfero user:
  145 +
  146 +$ RAILS_ENV=production rake multitenancy:reindex
  147 +
  148 +2. Move the uploaded files to the right place
  149 +
  150 +Add a directory with the same name as your schema name (by default this
  151 +name is 'public') in the root of each upload directory, for example,
  152 +public/articles/0000 will be moved to public/articles/public/0000. Do this
  153 +with the directories public/image_uploads, public/articles and public/thumbnails.
  154 +
  155 +3. Fix paths on activities
  156 +
  157 +The profile activities store static paths to the images, so it's necessary to fix
  158 +these paths. You can do this easily by setting an alias on your webserver.
  159 +On Apache you can add the three rules below, where 'public' is the schema name:
  160 +
  161 + RewriteRule ^/articles(.+) /articles/public$1
  162 + RewriteRule ^/image_uploads(.+) /image_uploads/public$1
  163 + RewriteRule ^/thumbnails(.+) /thumbnails/public$1
lib/acts_as_searchable.rb
@@ -2,7 +2,7 @@ module ActsAsSearchable @@ -2,7 +2,7 @@ module ActsAsSearchable
2 2
3 module ClassMethods 3 module ClassMethods
4 def acts_as_searchable(options = {}) 4 def acts_as_searchable(options = {})
5 - if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL' 5 + if Noosfero::MultiTenancy.on? and ActiveRecord::Base.postgresql?
6 options[:additional_fields] ||= {} 6 options[:additional_fields] ||= {}
7 options[:additional_fields] = Hash[*options[:additional_fields].collect{ |v| [v, {}] }.flatten] if options[:additional_fields].is_a?(Array) 7 options[:additional_fields] = Hash[*options[:additional_fields].collect{ |v| [v, {}] }.flatten] if options[:additional_fields].is_a?(Array)
8 options[:additional_fields].merge!(:schema_name => { :index => :untokenized }) 8 options[:additional_fields].merge!(:schema_name => { :index => :untokenized })
@@ -35,7 +35,7 @@ module ActsAsSearchable @@ -35,7 +35,7 @@ module ActsAsSearchable
35 35
36 ferret_options[:limit] = :all 36 ferret_options[:limit] = :all
37 37
38 - ferret_query = ActiveRecord::Base.connection.adapter_name == 'PostgreSQL' ? "+schema_name:\"#{schema_name}\" AND #{query}" : query 38 + ferret_query = (Noosfero::MultiTenancy.on? and ActiveRecord::Base.postgresql?) ? "+schema_name:\"#{schema_name}\" AND #{query}" : query
39 # FIXME this is a HORRIBLE HACK 39 # FIXME this is a HORRIBLE HACK
40 ids = find_ids_with_ferret(ferret_query, ferret_options)[1][0..8000].map{|r|r[:id].to_i} 40 ids = find_ids_with_ferret(ferret_query, ferret_options)[1][0..8000].map{|r|r[:id].to_i}
41 41
lib/noosfero/multi_tenancy.rb
@@ -6,7 +6,7 @@ module Noosfero @@ -6,7 +6,7 @@ module Noosfero
6 end 6 end
7 7
8 def self.on? 8 def self.on?
9 - !self.mapping.blank? 9 + !self.mapping.blank? || self.is_hosted_environment?
10 end 10 end
11 11
12 def self.db_by_host=(host) 12 def self.db_by_host=(host)
@@ -26,5 +26,11 @@ module Noosfero @@ -26,5 +26,11 @@ module Noosfero
26 map 26 map
27 end 27 end
28 28
  29 + def self.is_hosted_environment?
  30 + db_file = File.join(RAILS_ROOT, 'config', 'database.yml')
  31 + db_config = YAML.load_file(db_file)
  32 + db_config.select{ |env, attr| RAILS_ENV.to_s.match(/_#{env}$/) }.any?
  33 + end
  34 +
29 end 35 end
30 end 36 end
lib/postgresql_attachment_fu.rb
@@ -9,7 +9,7 @@ module PostgresqlAttachmentFu @@ -9,7 +9,7 @@ module PostgresqlAttachmentFu
9 module InstanceMethods 9 module InstanceMethods
10 def full_filename(thumbnail = nil) 10 def full_filename(thumbnail = nil)
11 file_system_path = (thumbnail ? thumbnail_class : self).attachment_options[:path_prefix].to_s 11 file_system_path = (thumbnail ? thumbnail_class : self).attachment_options[:path_prefix].to_s
12 - file_system_path = File.join(file_system_path, ActiveRecord::Base.connection.schema_search_path) if ActiveRecord::Base.postgresql? 12 + file_system_path = File.join(file_system_path, ActiveRecord::Base.connection.schema_search_path) if ActiveRecord::Base.postgresql? and Noosfero::MultiTenancy.on?
13 File.join(RAILS_ROOT, file_system_path, *partitioned_path(thumbnail_name_for(thumbnail))) 13 File.join(RAILS_ROOT, file_system_path, *partitioned_path(thumbnail_name_for(thumbnail)))
14 end 14 end
15 end 15 end
test/test_helper.rb
@@ -189,12 +189,14 @@ class Test::Unit::TestCase @@ -189,12 +189,14 @@ class Test::Unit::TestCase
189 adapter = ActiveRecord::Base.connection.class 189 adapter = ActiveRecord::Base.connection.class
190 adapter.any_instance.stubs(:adapter_name).returns('PostgreSQL') 190 adapter.any_instance.stubs(:adapter_name).returns('PostgreSQL')
191 adapter.any_instance.stubs(:schema_search_path).returns(schema_name) 191 adapter.any_instance.stubs(:schema_search_path).returns(schema_name)
  192 + Noosfero::MultiTenancy.stubs(:on?).returns(true)
192 reload_for_ferret 193 reload_for_ferret
193 end 194 end
194 195
195 def uses_sqlite 196 def uses_sqlite
196 adapter = ActiveRecord::Base.connection.class 197 adapter = ActiveRecord::Base.connection.class
197 adapter.any_instance.stubs(:adapter_name).returns('SQLite') 198 adapter.any_instance.stubs(:adapter_name).returns('SQLite')
  199 + Noosfero::MultiTenancy.stubs(:on?).returns(false)
198 end 200 end
199 201
200 def reload_for_ferret 202 def reload_for_ferret
vendor/plugins/acts_as_ferret/lib/acts_as_ferret.rb
@@ -204,7 +204,7 @@ module ActsAsFerret @@ -204,7 +204,7 @@ module ActsAsFerret
204 # these properties are somewhat vital to the plugin and shouldn't 204 # these properties are somewhat vital to the plugin and shouldn't
205 # be overwritten by the user: 205 # be overwritten by the user:
206 index_definition[:ferret].update( 206 index_definition[:ferret].update(
207 - :key => (ActiveRecord::Base.connection.adapter_name == 'PostgreSQL' ? [:id, :class_name, :schema_name] : [:id, :class_name]), 207 + :key => ((Noosfero::MultiTenancy.on? and ActiveRecord::Base.postgresql?) ? [:id, :class_name, :schema_name] : [:id, :class_name]),
208 :path => index_definition[:index_dir], 208 :path => index_definition[:index_dir],
209 :auto_flush => true, # slower but more secure in terms of locking problems TODO disable when running in drb mode? 209 :auto_flush => true, # slower but more secure in terms of locking problems TODO disable when running in drb mode?
210 :create_if_missing => true 210 :create_if_missing => true