module Backup module Database class PostgreSQL < Base class Error < Backup::Error; end ## # Name of the database that needs to get dumped. # To dump all databases, set this to `:all` or leave blank. # +username+ must be a PostgreSQL superuser to run `pg_dumpall`. attr_accessor :name ## # Credentials for the specified database attr_accessor :username, :password ## # If set the pg_dump(all) command is executed as the given user attr_accessor :sudo_user ## # Connectivity options attr_accessor :host, :port, :socket ## # URL includes credentials and connectivity options attr_accessor :url ## # Tables to skip while dumping the database. # If `name` is set to :all (or not specified), these are ignored. attr_accessor :skip_tables ## # Tables to dump. This in only valid if `name` is specified. # If none are given, the entire database will be dumped. attr_accessor :only_tables ## # Additional "pg_dump" or "pg_dumpall" options attr_accessor :additional_options def check_options return unless url ignored_options = { username: username, password: password, host: host, port: port, socket: socket, name: name }.reject { |_, value| value.nil? } return if ignored_options.empty? Logger.warn "PostgreSQL: the options " \ "#{ignored_options.keys.join(", ")} are set, but will be " \ "ignored because the `:url` option is set." end def initialize(model, database_id = nil, &block) super instance_eval(&block) if block_given? @name ||= :all # Warn user if url option is mixed with the others check_options end ## # Performs the pgdump command and outputs the dump file # in the +dump_path+ using +dump_filename+. # # /databases/PostgreSQL[-].sql[.gz] def perform! super pipeline = Pipeline.new dump_ext = "sql" pipeline << (dump_all? ? pgdumpall : pgdump) if model.compressor model.compressor.compress_with do |command, ext| pipeline << command dump_ext << ext end end pipeline << "#{utility(:cat)} > " \ "'#{File.join(dump_path, dump_filename)}.#{dump_ext}'" pipeline.run if pipeline.success? log!(:finished) else raise Error, "Dump Failed!\n" + pipeline.error_messages end end def pgdump password_option.to_s + sudo_option.to_s + "#{utility(:pg_dump)} #{pgdump_arguments}" end def pgdump_arguments if url.nil? "#{username_option} #{connectivity_options} #{user_options} #{tables_to_dump} " \ "#{tables_to_skip} #{name}" else "#{user_options} #{tables_to_dump} #{tables_to_skip} #{url}" end end def pgdumpall password_option.to_s + sudo_option.to_s + "#{utility(:pg_dumpall)} #{username_option} " \ "#{connectivity_options} #{user_options}" end def password_option "PGPASSWORD=#{Shellwords.escape(password)} " if password end def sudo_option "#{utility(:sudo)} -n -H -u #{sudo_user} " if sudo_user end def username_option "--username=#{Shellwords.escape(username)}" if username end def connectivity_options return "--host='#{socket}'" if socket opts = [] opts << "--host='#{host}'" if host opts << "--port='#{port}'" if port opts.join(" ") end def user_options Array(additional_options).join(" ") end def tables_to_dump Array(only_tables).map do |table| "--table='#{table}'" end.join(" ") end def tables_to_skip Array(skip_tables).map do |table| "--exclude-table='#{table}'" end.join(" ") end def dump_all? name == :all end end end end