Module: ForemanMaintain::Concerns::BaseDatabase

Defined in:
lib/foreman_maintain/concerns/base_database.rb

Instance Method Summary collapse

Instance Method Details

#backup_db_command(file_path, config = configuration) ⇒ Object

TODO: refactor to use dump_db



93
94
95
96
# File 'lib/foreman_maintain/concerns/base_database.rb', line 93

def backup_db_command(file_path, config = configuration)
  pg_dump_cmd = "pg_dump -Fc #{config['database']}"
  "runuser - postgres -c '#{pg_dump_cmd}' | bzip2 -9 > #{file_path}"
end

#backup_dirObject

TODO: remove the backup file path tools from here. Lib Utils::Backup?



99
100
101
# File 'lib/foreman_maintain/concerns/base_database.rb', line 99

def backup_dir
  @backup_dir ||= File.expand_path(ForemanMaintain.config.db_backup_dir)
end

#backup_file_path(config = configuration) ⇒ Object



50
51
52
53
# File 'lib/foreman_maintain/concerns/base_database.rb', line 50

def backup_file_path(config = configuration)
  dump_file_name = "#{config['database']}_#{Time.now.strftime('%Y-%m-%d_%H-%M-%S')}.dump"
  "#{backup_dir}/#{dump_file_name}.bz2"
end

#backup_global_objects(file) ⇒ Object



103
104
105
# File 'lib/foreman_maintain/concerns/base_database.rb', line 103

def backup_global_objects(file)
  execute!("runuser - postgres -c 'pg_dumpall -g > #{file}'")
end

#backup_local(backup_file, extra_tar_options = {}) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/foreman_maintain/concerns/base_database.rb', line 79

def backup_local(backup_file, extra_tar_options = {})
  dir = extra_tar_options.fetch(:data_dir, data_dir)
  FileUtils.cd(dir) do
    tar_options = {
      :archive => backup_file,
      :command => 'create',
      :transform => "s,^,#{data_dir[1..-1]},S",
      :files => '*'
    }.merge(extra_tar_options)
    feature(:tar).run(tar_options)
  end
end

#config_filesObject



16
17
18
19
20
# File 'lib/foreman_maintain/concerns/base_database.rb', line 16

def config_files
  [
    '/etc/systemd/system/postgresql.service'
  ]
end

#configurationObject

Raises:

  • (NotImplementedError)


12
13
14
# File 'lib/foreman_maintain/concerns/base_database.rb', line 12

def configuration
  raise NotImplementedError
end

#data_dirObject



4
5
6
7
8
9
10
# File 'lib/foreman_maintain/concerns/base_database.rb', line 4

def data_dir
  if check_min_version('foreman', '2.0')
    '/var/opt/rh/rh-postgresql12/lib/pgsql/data/'
  else
    '/var/lib/pgsql/data/'
  end
end

#db_version(config = configuration) ⇒ Object



154
155
156
157
158
159
160
161
162
163
# File 'lib/foreman_maintain/concerns/base_database.rb', line 154

def db_version(config = configuration)
  if ping(config)
    # Note - t removes headers, -A removes alignment whitespace
    server_version_cmd = psql_command(config) + ' -c "SHOW server_version" -t -A'
    version_string = execute!(server_version_cmd, :hidden_patterns => [config['password']])
    version(version_string)
  else
    raise_service_error
  end
end

#delete_records_by_ids(tbl_name, rec_ids) ⇒ Object



126
127
128
129
130
131
132
133
134
135
# File 'lib/foreman_maintain/concerns/base_database.rb', line 126

def delete_records_by_ids(tbl_name, rec_ids)
  quotize_rec_ids = rec_ids.map { |el| "'#{el}'" }.join(',')
  unless quotize_rec_ids.empty?
    psql(<<-SQL)
      BEGIN;
       DELETE FROM #{tbl_name} WHERE id IN (#{quotize_rec_ids});
      COMMIT;
    SQL
  end
end

#dropdb(config = configuration) ⇒ Object



141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/foreman_maintain/concerns/base_database.rb', line 141

def dropdb(config = configuration)
  if local?
    execute!("runuser - postgres -c 'dropdb #{config['database']}'")
  else
    delete_statement = psql(<<-SQL)
      select string_agg('drop table if exists \"' || tablename || '\" cascade;', '')
      from pg_tables
      where schemaname = 'public';
    SQL
    psql(delete_statement)
  end
end

#dump_db(file, config = configuration) ⇒ Object



55
56
57
# File 'lib/foreman_maintain/concerns/base_database.rb', line 55

def dump_db(file, config = configuration)
  execute!(dump_command(config) + " > #{file}", :hidden_patterns => [config['password']])
end

#find_base_directory(directory) ⇒ Object



137
138
139
# File 'lib/foreman_maintain/concerns/base_database.rb', line 137

def find_base_directory(directory)
  find_dir_containing_file(directory, 'postgresql.conf')
end

#local?(config = configuration) ⇒ Boolean

Returns:

  • (Boolean)


22
23
24
# File 'lib/foreman_maintain/concerns/base_database.rb', line 22

def local?(config = configuration)
  ['localhost', '127.0.0.1', `hostname`.strip].include? config['host']
end

#perform_backup(config = configuration) ⇒ Object



107
108
109
110
111
112
113
# File 'lib/foreman_maintain/concerns/base_database.rb', line 107

def perform_backup(config = configuration)
  file_path = backup_file_path(config)
  backup_cmd = backup_db_command(file_path, config)
  execute!(backup_cmd, :hidden_patterns => [config['password']])
  puts "\n Note: Database backup file path - #{file_path}"
  puts "\n In case of any exception, use above dump file to restore DB."
end

#ping(config = configuration) ⇒ Object



44
45
46
47
48
# File 'lib/foreman_maintain/concerns/base_database.rb', line 44

def ping(config = configuration)
  execute?(psql_command(config),
           :stdin => 'SELECT 1 as ping',
           :hidden_patterns => [config['password']])
end

#psql(query, config = configuration) ⇒ Object



34
35
36
37
38
39
40
41
42
# File 'lib/foreman_maintain/concerns/base_database.rb', line 34

def psql(query, config = configuration)
  if ping(config)
    execute(psql_command(config),
            :stdin => query,
            :hidden_patterns => [config['password']])
  else
    raise_service_error
  end
end

#psql_cmd_available?Boolean

Returns:

  • (Boolean)


165
166
167
168
# File 'lib/foreman_maintain/concerns/base_database.rb', line 165

def psql_cmd_available?
  exit_status, _output = execute_with_status('which psql')
  exit_status == 0
end

#query(sql, config = configuration) ⇒ Object



26
27
28
# File 'lib/foreman_maintain/concerns/base_database.rb', line 26

def query(sql, config = configuration)
  parse_csv(query_csv(sql, config))
end

#query_csv(sql, config = configuration) ⇒ Object



30
31
32
# File 'lib/foreman_maintain/concerns/base_database.rb', line 30

def query_csv(sql, config = configuration)
  psql(%{COPY (#{sql}) TO STDOUT WITH CSV HEADER}, config)
end

#raise_psql_missing_errorObject

Raises:



170
171
172
173
# File 'lib/foreman_maintain/concerns/base_database.rb', line 170

def raise_psql_missing_error
  raise Error::Fail, 'The psql command not found.'\
          ' Make sure system has psql utility installed.'
end

#restore_dump(file, localdb, config = configuration) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/foreman_maintain/concerns/base_database.rb', line 59

def restore_dump(file, localdb, config = configuration)
  if localdb
    dump_cmd = "runuser - postgres -c 'pg_restore -C -d postgres #{file}'"
    execute!(dump_cmd)
  else
    # TODO: figure out how to completely ignore errors. Currently this
    # sometimes exits with 1 even though errors are ignored by pg_restore
    dump_cmd = base_command(config, 'pg_restore') +
               ' --no-privileges --clean --disable-triggers -n public ' \
               "-d #{config['database']} #{file}"
    execute!(dump_cmd, :hidden_patterns => [config['password']],
                       :valid_exit_statuses => [0, 1])
  end
end

#restore_pg_globals(pg_globals, config = configuration) ⇒ Object



74
75
76
77
# File 'lib/foreman_maintain/concerns/base_database.rb', line 74

def restore_pg_globals(pg_globals, config = configuration)
  execute!(base_command(config, 'psql') + " -f #{pg_globals} postgres 2>/dev/null",
           :hidden_patterns => [config['password']])
end

#table_exist?(table_name) ⇒ Boolean

Returns:

  • (Boolean)


115
116
117
118
119
120
121
122
123
124
# File 'lib/foreman_maintain/concerns/base_database.rb', line 115

def table_exist?(table_name)
  sql = <<-SQL
    SELECT EXISTS ( SELECT *
    FROM information_schema.tables WHERE table_name =  '#{table_name}' )
  SQL
  result = query(sql)
  return false if result.nil? || (result && result.empty?)

  result.first['exists'].eql?('t')
end