module ForemanMaintain::Concerns::BaseDatabase

Public Instance Methods

amcheck() click to toggle source
# File lib/foreman_maintain/concerns/base_database.rb, line 143
      def amcheck
        # executing the check requires superuser privileges
        return unless local?

        return unless amcheck_installed?

        psqlcmd = "runuser - postgres -c 'psql --set=ON_ERROR_STOP=on #{configuration['database']}'"

        amcheck_query = <<~SQL
          SELECT bt_index_check(index => c.oid, heapallindexed => i.indisunique),
               c.relname,
               c.relpages
          FROM pg_index i
          JOIN pg_opclass op ON i.indclass[0] = op.oid
          JOIN pg_am am ON op.opcmethod = am.oid
          JOIN pg_class c ON i.indexrelid = c.oid
          JOIN pg_namespace n ON c.relnamespace = n.oid
          WHERE am.amname = 'btree' AND n.nspname = 'public'
          -- Don't check temp tables, which may be from another session:
          AND c.relpersistence != 't'
          -- Function may throw an error when this is omitted:
          AND c.relkind = 'i' AND i.indisready AND i.indisvalid
          ORDER BY c.relpages DESC;
        SQL

        execute_with_status(psqlcmd, :stdin => amcheck_query)
      end
amcheck_installed?() click to toggle source
# File lib/foreman_maintain/concerns/base_database.rb, line 171
def amcheck_installed?
  sql = "select 'amcheck_installed' from pg_extension where extname='amcheck'"
  result = query(sql)
  !result.nil? && !result.empty?
end
backup_dir() click to toggle source

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

# File lib/foreman_maintain/concerns/base_database.rb, line 107
def backup_dir
  @backup_dir ||= File.expand_path(ForemanMaintain.config.db_backup_dir)
end
backup_local(backup_file, extra_tar_options = {}) click to toggle source
# File lib/foreman_maintain/concerns/base_database.rb, line 90
def backup_local(backup_file, extra_tar_options = {})
  dir = extra_tar_options.fetch(:data_dir, data_dir)
  restore_dir = extra_tar_options.fetch(:restore_dir, data_dir)
  command = extra_tar_options.fetch(:command, 'create')

  FileUtils.cd(dir) do
    tar_options = {
      :archive => backup_file,
      :command => command,
      :transform => "s,^,#{restore_dir[1..]},S",
      :files => '*',
    }.merge(extra_tar_options)
    feature(:tar).run(tar_options)
  end
end
configuration() click to toggle source
# File lib/foreman_maintain/concerns/base_database.rb, line 41
def configuration
  raise NotImplementedError
end
data_dir() click to toggle source
# File lib/foreman_maintain/concerns/base_database.rb, line 4
def data_dir
  if debian_or_ubuntu?
    deb_postgresql_data_dir
  else
    '/var/lib/pgsql/data/'
  end
end
db_version() click to toggle source
# File lib/foreman_maintain/concerns/base_database.rb, line 124
def db_version
  ping!

  query = 'SHOW server_version'
  server_version_cmd = 'psql --tuples-only --no-align'
  version_string = execute!(server_version_cmd, :stdin => query, :env => base_env)
  version(version_string)
end
deb_postgresql_config_dirs() click to toggle source
# File lib/foreman_maintain/concerns/base_database.rb, line 35
def deb_postgresql_config_dirs
  deb_postgresql_versions.map do |ver|
    "/etc/postgresql/#{ver}/main/"
  end
end
deb_postgresql_data_dir() click to toggle source
# File lib/foreman_maintain/concerns/base_database.rb, line 12
def deb_postgresql_data_dir
  deb_postgresql_versions.map do |ver|
    "/var/lib/postgresql/#{ver}/main/"
  end
end
deb_postgresql_versions() click to toggle source
# File lib/foreman_maintain/concerns/base_database.rb, line 18
def deb_postgresql_versions
  @deb_postgresql_versions ||= begin
    installed_pkgs = package_manager.list_installed_packages('${binary:Package}\n')
    installed_pkgs.grep(/^postgresql-\d+$/).map do |name|
      name.split('-').last
    end
  end
end
dropdb() click to toggle source
# File lib/foreman_maintain/concerns/base_database.rb, line 111
      def dropdb
        if local?
          execute!("runuser - postgres -c 'dropdb #{configuration['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) click to toggle source
# File lib/foreman_maintain/concerns/base_database.rb, line 71
def dump_db(file)
  dump_command = "pg_dump -Fc -f #{file}"
  execute!(dump_command, :env => base_env)
end
local?() click to toggle source
# File lib/foreman_maintain/concerns/base_database.rb, line 45
def local?
  ['localhost', '127.0.0.1', `hostname`.strip].include?(configuration['host'])
end
ping() click to toggle source
# File lib/foreman_maintain/concerns/base_database.rb, line 65
def ping
  execute?('psql',
    :stdin => 'SELECT 1 as ping',
    :env => base_env)
end
postgresql_conf() click to toggle source
# File lib/foreman_maintain/concerns/base_database.rb, line 27
def postgresql_conf
  return "#{data_dir}/postgresql.conf" if el?

  deb_postgresql_config_dirs.map do |conf_dir|
    "#{conf_dir}postgresql.conf"
  end
end
psql(query) click to toggle source
# File lib/foreman_maintain/concerns/base_database.rb, line 57
def psql(query)
  ping!

  execute('psql',
    :stdin => query,
    :env => base_env)
end
psql_cmd_available?() click to toggle source
# File lib/foreman_maintain/concerns/base_database.rb, line 133
def psql_cmd_available?
  exit_status, _output = execute_with_status('which psql')
  exit_status == 0
end
query(sql) click to toggle source
# File lib/foreman_maintain/concerns/base_database.rb, line 49
def query(sql)
  parse_csv(query_csv(sql))
end
query_csv(sql) click to toggle source
# File lib/foreman_maintain/concerns/base_database.rb, line 53
def query_csv(sql)
  psql(%{COPY (#{sql}) TO STDOUT WITH CSV HEADER})
end
raise_psql_missing_error() click to toggle source
# File lib/foreman_maintain/concerns/base_database.rb, line 138
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) click to toggle source
# File lib/foreman_maintain/concerns/base_database.rb, line 76
def restore_dump(file, localdb)
  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 = 'pg_restore --no-privileges --clean --disable-triggers -n public ' \
               "-d #{configuration['database']} #{file}"
    execute!(dump_cmd, :env => base_env,
      :valid_exit_statuses => [0, 1])
  end
end

Private Instance Methods

base_env() click to toggle source
# File lib/foreman_maintain/concerns/base_database.rb, line 179
def base_env
  {
    'PGHOST' => configuration.fetch('host', 'localhost'),
    'PGPORT' => configuration['port']&.to_s,
    'PGUSER' => configuration['username'],
    'PGPASSWORD' => configuration['password'],
    'PGDATABASE' => configuration['database'],
  }
end
ping!() click to toggle source
# File lib/foreman_maintain/concerns/base_database.rb, line 189
def ping!
  unless ping
    raise Error::Fail, 'Please check whether database service is up & running state.'
  end
end