Module: BackupRestore
- Defined in:
- lib/backup_restore.rb,
lib/backup_restore/logger.rb,
lib/backup_restore/factory.rb,
lib/backup_restore/backuper.rb,
lib/backup_restore/restorer.rb,
lib/backup_restore/backup_store.rb,
lib/backup_restore/s3_backup_store.rb,
lib/backup_restore/system_interface.rb,
lib/backup_restore/uploads_restorer.rb,
lib/backup_restore/database_restorer.rb,
lib/backup_restore/meta_data_handler.rb,
lib/backup_restore/local_backup_store.rb,
lib/backup_restore/backup_file_handler.rb
Defined Under Namespace
Classes: BackupFileHandler, BackupStore, Backuper, DatabaseConfiguration, DatabaseRestorer, Factory, LocalBackupStore, Logger, MetaDataHandler, OperationRunningError, Restorer, RunningSidekiqJobsError, S3BackupStore, SystemInterface, UploadsRestorer
Constant Summary
collapse
- VERSION_PREFIX =
"v"
- DUMP_FILE =
"dump.sql.gz"
- LOGS_CHANNEL =
"/admin/backups/logs"
- RestoreDisabledError =
Class.new(RuntimeError)
- FilenameMissingError =
Class.new(RuntimeError)
- UploadsRestoreError =
Class.new(RuntimeError)
- DatabaseRestoreError =
Class.new(RuntimeError)
- MetaDataError =
Class.new(RuntimeError)
- MigrationRequiredError =
Class.new(RuntimeError)
Class Method Summary
collapse
Class Method Details
.backup!(user_id, opts = {}) ⇒ Object
11
12
13
14
15
16
17
|
# File 'lib/backup_restore.rb', line 11
def self.backup!(user_id, opts = {})
if opts[:fork] == false
BackupRestore::Backuper.new(user_id, opts).run
else
spawn_process!(:backup, user_id, opts)
end
end
|
.can_rollback? ⇒ Boolean
51
52
53
|
# File 'lib/backup_restore.rb', line 51
def self.can_rollback?
backup_tables_count > 0
end
|
.cancel! ⇒ Object
28
29
30
31
|
# File 'lib/backup_restore.rb', line 28
def self.cancel!
set_shutdown_signal!
true
end
|
.current_version ⇒ Object
68
69
70
|
# File 'lib/backup_restore.rb', line 68
def self.current_version
ActiveRecord::Migrator.current_version
end
|
.database_configuration ⇒ Object
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
# File 'lib/backup_restore.rb', line 125
def self.database_configuration
config = ActiveRecord::Base.connection_pool.db_config.configuration_hash
config = config.with_indifferent_access
if Rails.env.test?
username = ENV["PGUSER"]
password = ENV["PGPASSWORD"]
end
DatabaseConfiguration.new(
config["backup_host"] || config["host"],
config["backup_port"] || config["port"],
config["username"] || username || ENV["USER"] || "postgres",
config["password"] || password,
config["database"],
)
end
|
.is_operation_running? ⇒ Boolean
39
40
41
|
# File 'lib/backup_restore.rb', line 39
def self.is_operation_running?
!!Discourse.redis.get(running_key)
end
|
.logs ⇒ Object
63
64
65
66
|
# File 'lib/backup_restore.rb', line 63
def self.logs
id = start_logs_message_id
MessageBus.backlog(LOGS_CHANNEL, id).map { |m| m.data }
end
|
.mark_as_not_running! ⇒ Object
43
44
45
|
# File 'lib/backup_restore.rb', line 43
def self.mark_as_not_running!
Discourse.redis.del(running_key)
end
|
.mark_as_running! ⇒ Object
33
34
35
36
37
|
# File 'lib/backup_restore.rb', line 33
def self.mark_as_running!
Discourse.redis.setex(running_key, 60, "1")
save_start_logs_message_id
keep_it_running
end
|
.move_tables_between_schemas(source, destination) ⇒ Object
76
77
78
79
80
81
82
|
# File 'lib/backup_restore.rb', line 76
def self.move_tables_between_schemas(source, destination)
owner = database_configuration.username
ActiveRecord::Base.transaction do
DB.exec(move_tables_between_schemas_sql(source, destination, owner))
end
end
|
.move_tables_between_schemas_sql(source, destination, owner) ⇒ Object
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
# File 'lib/backup_restore.rb', line 84
def self.move_tables_between_schemas_sql(source, destination, owner)
<<~SQL
DO $$DECLARE row record;
BEGIN
-- create <destination> schema if it does not exists already
-- NOTE: DROP & CREATE SCHEMA is easier, but we don't want to drop the public schema
-- otherwise extensions (like hstore & pg_trgm) won't work anymore...
CREATE SCHEMA IF NOT EXISTS #{destination};
-- move all <source> tables to <destination> schema
FOR row IN SELECT tablename FROM pg_tables WHERE schemaname = '#{source}' AND tableowner = '#{owner}'
LOOP
EXECUTE 'DROP TABLE IF EXISTS #{destination}.' || quote_ident(row.tablename) || ' CASCADE;';
EXECUTE 'ALTER TABLE #{source}.' || quote_ident(row.tablename) || ' SET SCHEMA #{destination};';
END LOOP;
-- move all <source> views to <destination> schema
FOR row IN SELECT viewname FROM pg_views WHERE schemaname = '#{source}' AND viewowner = '#{owner}'
LOOP
EXECUTE 'DROP VIEW IF EXISTS #{destination}.' || quote_ident(row.viewname) || ' CASCADE;';
EXECUTE 'ALTER VIEW #{source}.' || quote_ident(row.viewname) || ' SET SCHEMA #{destination};';
END LOOP;
-- move all <source> materialized views to <destination> schema
FOR row IN SELECT matviewname FROM pg_matviews WHERE schemaname = '#{source}' AND matviewowner = '#{owner}'
LOOP
EXECUTE 'DROP MATERIALIZED VIEW IF EXISTS #{destination}.' || quote_ident(row.matviewname) || ' CASCADE;';
EXECUTE 'ALTER MATERIALIZED VIEW #{source}.' || quote_ident(row.matviewname) || ' SET SCHEMA #{destination};';
END LOOP;
-- move all <source> enums to <destination> enums
FOR row IN (
SELECT typname FROM pg_type t
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
WHERE typcategory = 'E' AND n.nspname = '#{source}' AND pg_catalog.pg_get_userbyid(typowner) = '#{owner}'
) LOOP
EXECUTE 'DROP TYPE IF EXISTS #{destination}.' || quote_ident(row.typname) || ' CASCADE;';
EXECUTE 'ALTER TYPE #{source}.' || quote_ident(row.typname) || ' SET SCHEMA #{destination};';
END LOOP;
END$$;
SQL
end
|
.operations_status ⇒ Object
55
56
57
58
59
60
61
|
# File 'lib/backup_restore.rb', line 55
def self.operations_status
{
is_operation_running: is_operation_running?,
can_rollback: can_rollback?,
allow_restore: Rails.env.development? || SiteSetting.allow_restore,
}
end
|
.postgresql_major_version ⇒ Object
72
73
74
|
# File 'lib/backup_restore.rb', line 72
def self.postgresql_major_version
DB.query_single("SHOW server_version").first[/\d+/].to_i
end
|
.restore!(user_id, opts = {}) ⇒ Object
19
20
21
|
# File 'lib/backup_restore.rb', line 19
def self.restore!(user_id, opts = {})
spawn_process!(:restore, user_id, opts)
end
|
.should_shutdown? ⇒ Boolean
47
48
49
|
# File 'lib/backup_restore.rb', line 47
def self.should_shutdown?
!!Discourse.redis.get(shutdown_signal_key)
end
|