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



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

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?



106
107
108
# File 'lib/foreman_maintain/concerns/base_database.rb', line 106

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

#backup_file_path(config = configuration) ⇒ Object



57
58
59
60
# File 'lib/foreman_maintain/concerns/base_database.rb', line 57

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



110
111
112
# File 'lib/foreman_maintain/concerns/base_database.rb', line 110

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

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



86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/foreman_maintain/concerns/base_database.rb', line 86

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



23
24
25
26
27
# File 'lib/foreman_maintain/concerns/base_database.rb', line 23

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

#configurationObject

Raises:

  • (NotImplementedError)


19
20
21
# File 'lib/foreman_maintain/concerns/base_database.rb', line 19

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 el7? && package_manager.installed?('rh-postgresql12-postgresql-server-syspaths')
    '/var/opt/rh/rh-postgresql12/lib/pgsql/data/'
  else
    '/var/lib/pgsql/data/'
  end
end

#db_version(config = configuration) ⇒ Object



161
162
163
164
165
166
167
168
169
170
# File 'lib/foreman_maintain/concerns/base_database.rb', line 161

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



133
134
135
136
137
138
139
140
141
142
# File 'lib/foreman_maintain/concerns/base_database.rb', line 133

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



148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/foreman_maintain/concerns/base_database.rb', line 148

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



62
63
64
# File 'lib/foreman_maintain/concerns/base_database.rb', line 62

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

#find_base_directory(directory) ⇒ Object



144
145
146
# File 'lib/foreman_maintain/concerns/base_database.rb', line 144

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

#local?(config = configuration) ⇒ Boolean

Returns:

  • (Boolean)


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

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

#perform_backup(config = configuration) ⇒ Object



114
115
116
117
118
119
120
# File 'lib/foreman_maintain/concerns/base_database.rb', line 114

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



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

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

#psql(query, config = configuration) ⇒ Object



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

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)


172
173
174
175
# File 'lib/foreman_maintain/concerns/base_database.rb', line 172

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

#query(sql, config = configuration) ⇒ Object



33
34
35
# File 'lib/foreman_maintain/concerns/base_database.rb', line 33

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

#query_csv(sql, config = configuration) ⇒ Object



37
38
39
# File 'lib/foreman_maintain/concerns/base_database.rb', line 37

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

#raise_psql_missing_errorObject

Raises:



177
178
179
180
# File 'lib/foreman_maintain/concerns/base_database.rb', line 177

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



66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/foreman_maintain/concerns/base_database.rb', line 66

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



81
82
83
84
# File 'lib/foreman_maintain/concerns/base_database.rb', line 81

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

#restore_transformObject



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

def restore_transform
  if el8?
    # this allows to transform an EL7 backup to EL8 paths
    's,^var/opt/rh/rh-postgresql12/,var/,S'
  end
end

#table_exist?(table_name) ⇒ Boolean

Returns:

  • (Boolean)


122
123
124
125
126
127
128
129
130
131
# File 'lib/foreman_maintain/concerns/base_database.rb', line 122

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