class Backup::RemoteArchive

Attributes

server_backup_path[RW]
server_host[RW]

server options

server_ssh_options[RW]

Public Class Methods

new(model, name, &block) click to toggle source

Adds a new Archive to a Backup Model.

Backup::Model.new(:my_backup, 'My Backup') do
  remote_archive :my_archive do |archive|
    archive.add 'path/to/archive'
    archive.add '/another/path/to/archive'
    archive.exclude 'path/to/exclude'
    archive.exclude '/another/path/to/exclude'
  end
end

All paths added using `add` or `exclude` will be expanded to their full paths from the root of the filesystem. Files will be added to the tar archive using these full paths, and their leading `/` will be preserved (using tar's `-P` option).

/path/to/pwd/path/to/archive/...
/another/path/to/archive/...

When a `root` path is given, paths to add/exclude are taken as relative to the `root` path, unless given as absolute paths.

Backup::Model.new(:my_backup, 'My Backup') do
  archive :my_archive do |archive|
    archive.root '~/my_data'
    archive.add 'path/to/archive'
    archive.add '/another/path/to/archive'
    archive.exclude 'path/to/exclude'
    archive.exclude '/another/path/to/exclude'
  end
end

This directs `tar` to change directories to the `root` path to create the archive. Unless paths were given as absolute, the paths within the archive will be relative to the `root` path.

path/to/archive/...
/another/path/to/archive/...

For absolute paths added to this archive, the leading `/` will be preserved. Take note that when archives are extracted, leading `/` are stripped by default, so care must be taken when extracting archives with mixed relative/absolute paths.

# File lib/backup/remote_archive.rb, line 70
def initialize(model, name, &block)
  @model   = model
  @name    = name.to_s
  @options = {
    :sudo        => false,
    :root        => false,
    :paths       => [],
    :excludes    => [],
    :tar_options => ''
  }

  DSL.new(@options).instance_eval(&block)

  # server options
  self.server_host = @options[:server_host]
  ssh_options = {}
  v = @options[:server_ssh_user]
  ssh_options[:user] = v if v

  v = @options[:server_ssh_password]
  ssh_options[:password] = v if v

  v = @options[:server_ssh_key]
  ssh_options[:key] = v if v

  v = @options[:server_ssh_port]
  ssh_options[:port] = v if v


  self.server_ssh_options = ssh_options
end

Public Instance Methods

perform!() click to toggle source
# File lib/backup/remote_archive.rb, line 102
def perform!
  Logger.info "Creating Archive '#{ name }'..."

  #
  path = File.join(Config.tmp_path, @model.trigger, 'archives')
  FileUtils.mkdir_p(path)


  #
  remote = Backup::Remote::Command.new

  pipeline = Pipeline.new
  with_files_from(paths_to_package) do |files_from|
    # upload to server
    res_upload = remote.ssh_upload_file(server_host, server_ssh_options, files_from, files_from)

    if res_upload[:res]==0
      raise "Cannot upload file to server - #{files_from}"
    end

    #
    pipeline.add(
      "#{ tar_command } #{ tar_options } -cPf -#{ tar_root } " +
      "#{ paths_to_exclude } -T '#{ files_from }'",
      tar_success_codes
    )

    extension = 'tar'
    @model.compressor.compress_with do |command, ext|
      pipeline << command
      extension << ext
    end if @model.compressor

    #
    archive_file = File.join(path, "#{ name }.#{ extension }")
    remote_archive_file = File.join('/tmp', "#{ name }.#{ extension }")
    pipeline << "#{ utility(:cat) } > '#{ remote_archive_file }'"


    #pipeline.run

    # generate backup on remote server
    cmd_remote = pipeline.commands.join(" | ")

    #puts "remote cmd: #{cmd_remote}"
    #exit


    res_generate = remote.run_ssh_cmd(server_host, server_ssh_options, cmd_remote)

    if res_generate[:res]==0
      raise 'Cannot create backup on server'
    end

    # download backup
    res_download = remote.ssh_download_file(server_host, server_ssh_options, remote_archive_file, archive_file)

    #puts "res: #{res_download}"

    if res_download[:res]==0
      raise 'Cannot download file from server'
    end

    # delete archive on server
    res_delete = remote.run_ssh_cmd(server_host, server_ssh_options, "rm #{remote_archive_file}")

  end

  Logger.info "Archive '#{ name }' Complete!"

  #if pipeline.success?
  #  Logger.info "Archive '#{ name }' Complete!"
  #else
  #  raise Error, "Failed to Create Archive '#{ name }'\n" + pipeline.error_messages
  #end
end

Private Instance Methods

paths_to_exclude() click to toggle source
# File lib/backup/remote_archive.rb, line 205
def paths_to_exclude
  options[:excludes].map {|path|
    "--exclude='#{ prepare_path(path) }'"
  }.join(' ')
end
paths_to_package() click to toggle source
# File lib/backup/remote_archive.rb, line 190
def paths_to_package
  options[:paths].map {|path| prepare_path(path) }
end
prepare_path(path) click to toggle source
# File lib/backup/remote_archive.rb, line 211
def prepare_path(path)
  options[:root] ? path : File.expand_path(path)
end
tar_command() click to toggle source
# File lib/backup/remote_archive.rb, line 181
def tar_command
  tar = utility(:tar)
  options[:sudo] ? "#{ utility(:sudo) } -n #{ tar }" : tar
end
tar_options() click to toggle source
# File lib/backup/remote_archive.rb, line 215
def tar_options
  args = options[:tar_options]
  gnu_tar? ? "--ignore-failed-read #{ args }".strip : args
end
tar_root() click to toggle source
# File lib/backup/remote_archive.rb, line 186
def tar_root
  options[:root] ? " -C '#{ File.expand_path(options[:root]) }'" : ''
end
tar_success_codes() click to toggle source
# File lib/backup/remote_archive.rb, line 220
def tar_success_codes
  gnu_tar? ? [0, 1] : [0]
end
with_files_from(paths) { |"#{ path }"| ... } click to toggle source
# File lib/backup/remote_archive.rb, line 194
def with_files_from(paths)
  tmpfile = Tempfile.new('backup-archive-paths')
  paths.each {|path| tmpfile.puts path }
  tmpfile.close

  #yield "-T '#{ tmpfile.path }'"
  yield "#{ tmpfile.path }"
ensure
  tmpfile.delete
end