Class: EY::Backup::Postgresql
- Inherits:
-
Engine
show all
- Defined in:
- lib/ey_backup/engines/postgresql_engine.rb
Constant Summary
Constants included
from Spawner
Spawner::CHUNK_SIZE
Instance Attribute Summary
Attributes inherited from Engine
#allow_concurrent, #force, #host, #key_id, #log_coordinates, #password, #skip_analyze, #username
Instance Method Summary
collapse
Methods inherited from Engine
#backup_running?, #block_concurrent, descendants, #gpg?, inherited, #initialize, label, lookup, register
Methods included from Spawner
#ioify, #run, #runs?, #spawn
Methods inherited from Base
#logger
Instance Method Details
#cancel_connections(database_name) ⇒ Object
72
73
74
75
76
|
# File 'lib/ey_backup/engines/postgresql_engine.rb', line 72
def cancel_connections(database_name)
%x{psql -U#{username} -h #{host} postgres -c"SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = '#{database_name}';"}
end
|
#check_connections(database_name) ⇒ Object
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
# File 'lib/ey_backup/engines/postgresql_engine.rb', line 52
def check_connections(database_name)
active_connections = %x{PGPASSWORD='#{password}' psql -U#{username} -h #{host} -t postgres -c "select count(*) from pg_stat_activity where datname='#{database_name}';"}
if active_connections.to_i > 0
res = ''
unless force
puts "There are currently #{active_connections} connections on database: '#{database_name}'; can I kill these to continue (Y/n):"
Timeout::timeout(30){
res = gets.strip
}
end
if res.upcase == 'Y' or force
cancel_connections(database_name)
else
EY::Backup.logger.fatal(%Q{ERROR: Target database has active connections. For more information, see "Restore or load a database" in docs.engineyard.com})
end
end
end
|
#check_if_replica ⇒ Object
90
91
92
93
94
95
96
97
|
# File 'lib/ey_backup/engines/postgresql_engine.rb', line 90
def check_if_replica
command = "PGPASSWORD='#{password}' psql -U#{username} -h #{host} -t -c 'select pg_is_in_recovery()' postgres| head -n 1"
verbose "Checking for replica state with: #{command}"
stdout = %x{#{command}}
unless stdout.chomp =~ /^\W*f$/
EY::Backup.logger.fatal(%Q{ERROR: Target host: '#{host}' is currently a replica in recovery mode; restore operations need to be processed against the master.})
end
end
|
#create_command(database_name) ⇒ Object
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
# File 'lib/ey_backup/engines/postgresql_engine.rb', line 106
def create_command(database_name)
command="PGPASSWORD='#{password}' psql -U#{username} -h #{host} -t postgres -c \"SELECT 'CREATE DATABASE ' || datname ||
' WITH OWNER ' || pg_user.usename ||
CASE (select pg_encoding_to_char(encoding) from pg_database where datname='template1')
WHEN pg_encoding_to_char(encoding)
THEN ''
ELSE ' template=template0'
END ||
' ENCODING ''' || pg_encoding_to_char(encoding) ||
''' LC_COLLATE ''' || datcollate||
''' LC_CTYPE ''' || datctype ||
''' CONNECTION LIMIT ' || datconnlimit || ';'
FROM pg_database
INNER JOIN pg_user
ON pg_user.usesysid = pg_database.datdba
WHERE datname = '#{database_name}'\""
verbose "Getting create info: #{command}"
%x{#{command}}
end
|
#create_database(database_name) ⇒ Object
84
85
86
87
88
|
# File 'lib/ey_backup/engines/postgresql_engine.rb', line 84
def create_database(database_name)
command = "PGPASSWORD='#{password}' createdb -U#{username} -h #{host} #{database_name}"
verbose "Creating Database with: #{command}"
%x{#{command}}
end
|
#cycle_database(database_name) ⇒ Object
126
127
128
129
130
131
132
133
134
135
|
# File 'lib/ey_backup/engines/postgresql_engine.rb', line 126
def cycle_database(database_name)
create_cmd = create_command(database_name).chomp
if create_cmd == ''
create_database(database_name)
else
check_connections(database_name)
drop_database(database_name)
%x{PGPASSWORD='#{password}' psql -U#{username} -h #{host} -t postgres -c "#{create_cmd}"}
end
end
|
#drop_database(database_name) ⇒ Object
78
79
80
81
82
|
# File 'lib/ey_backup/engines/postgresql_engine.rb', line 78
def drop_database(database_name)
command = "PGPASSWORD='#{password}' dropdb -h #{host} -U#{username} #{database_name}"
verbose "Dropping Database with: #{command}"
%x{#{command}}
end
|
#dump(database_name, basename) ⇒ Object
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
# File 'lib/ey_backup/engines/postgresql_engine.rb', line 6
def dump(database_name, basename)
file = basename + '.dump'
command = "PGPASSWORD='#{password}' pg_dump -h #{host} --create --format=c -U#{username} #{database_name} "
if gpg?
command << " | " << GPGEncryptor.command_for(key_id)
file << GPGEncryptor.extension
end
command << " > #{file}"
block_concurrent(database_name) unless allow_concurrent
run(command, database_name)
file
end
|
#load(database_name, file) ⇒ Object
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
# File 'lib/ey_backup/engines/postgresql_engine.rb', line 24
def load(database_name, file)
if file =~ /.gpz$/ abort "\nCannot restore a GPG backup directly; decrypt the file (#{file}) using your key and then load with pg_restore.
To decrypt a backup: https://support.cloud.engineyard.com/hc/en-us/articles/205413948-Use-PGP-Encrypted-Database-Backups-with-Engine-Yard-Cloud#restore
Once decrypted, restore with: `pg_restore -h #{host} --format=c --clean -U#{username} -d #{database_name} <filename>`\n\n"
end
cycle_database(database_name)
toc_file = "#{file}.toc"
table_of_contents(file, toc_file)
command = "cat #{file}"
command << " | PGPASSWORD='#{password}' pg_restore -L #{toc_file} -h #{host} --format=c -U#{username} -d #{database_name}"
run(command, database_name)
system("rm #{toc_file}") if File.exists?(toc_file)
unless skip_analyze
verbose "Analyzing database '#{database_name}', use --skip-analyze to skip this step."
%x{PGPASSWORD='#{password}' vacuumdb -h #{host} -U#{username} -d #{database_name} --analyze-only}
end
end
|
#suffix ⇒ Object
137
138
139
|
# File 'lib/ey_backup/engines/postgresql_engine.rb', line 137
def suffix
/\.(dump|gpz)$/
end
|
#table_of_contents(file, toc_file) ⇒ Object
99
100
101
102
103
104
|
# File 'lib/ey_backup/engines/postgresql_engine.rb', line 99
def table_of_contents(file, toc_file)
command = %Q{pg_restore -l #{file} | sed -e 's/^\\\(.* COMMENT - EXTENSION .*\\\)/;\\1/g' \
-e 's/^\\\(.* rdsadmin$\\\)/;\\1/g' > #{toc_file}}
verbose "Creating table of contents: #{command}"
%x{#{command}}
end
|