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

#force, #host, #key_id, #password, #username

Instance Method Summary collapse

Methods inherited from Engine

descendants, #gpg?, inherited, #initialize, label, lookup, register

Methods included from Spawner

#ioify, #run, #runs?, #spawn

Methods inherited from Base

#logger

Constructor Details

This class inherits a constructor from EY::Backup::Engine

Instance Method Details

#cancel_connections(database_name) ⇒ Object



57
58
59
60
61
# File 'lib/ey_backup/engines/postgresql_engine.rb', line 57

def cancel_connections(database_name)
  %x{psql -U postgres -h #{host} -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



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/ey_backup/engines/postgresql_engine.rb', line 37

def check_connections(database_name)
  active_connections = %x{PGPASSWORD='#{password}' psql -U postgres -h #{host} -t -c "select count(*) from pg_stat_activity where datname='#{database_name}';"}
  
  if active_connections.to_i > 0
    res = ''
    unless force
      puts "There are currently #{stdout.string.to_i} 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_replicaObject



75
76
77
78
79
80
# File 'lib/ey_backup/engines/postgresql_engine.rb', line 75

def check_if_replica
  stdout = %x{PGPASSWORD='#{password}' psql -U postgres -h #{host} -t -c "select pg_is_in_recovery()"| head -n 1}
  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



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/ey_backup/engines/postgresql_engine.rb', line 82

def create_command(database_name)
  %x{PGPASSWORD='#{password}' psql -U postgres -h #{host} -t -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}'"
  }
end

#create_database(database_name) ⇒ Object



69
70
71
72
73
# File 'lib/ey_backup/engines/postgresql_engine.rb', line 69

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



101
102
103
104
105
106
107
108
109
110
# File 'lib/ey_backup/engines/postgresql_engine.rb', line 101

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 postgres -h #{host} -t -c "#{create_cmd}"}
  end
end

#drop_database(database_name) ⇒ Object



63
64
65
66
67
# File 'lib/ey_backup/engines/postgresql_engine.rb', line 63

def drop_database(database_name)
  command = "PGPASSWORD='#{password}' dropdb -h #{host} -Upostgres #{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
# 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 -Upostgres #{database_name} 2> /tmp/eybackup.$$.dumperr"

  if gpg?
    command << " | " << GPGEncryptor.command_for(key_id)
    file << GPGEncryptor.extension
  end

  command << " > #{file}"

  run(command, database_name)

  file
end

#load(database_name, file) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/ey_backup/engines/postgresql_engine.rb', line 23

def load(database_name, file)
  if file =~ /.gpz$/ # GPG?
    abort "Cannot restore a GPG backup directly; decrypt the file (#{file}) using your key and then load with pg_restore."
  end

  cycle_database(database_name)

  command = "cat #{file}"

  command << " | PGPASSWORD='#{password}' pg_restore -h #{host} --format=c -Upostgres -d #{database_name} 2> /tmp/eybackup.$$.dumperr"

  run(command, database_name)
end

#suffixObject



112
113
114
# File 'lib/ey_backup/engines/postgresql_engine.rb', line 112

def suffix
  /\.(dump|gpz)$/
end