diff --git a/astrails-safe.gemspec b/astrails-safe.gemspec index 2345716..d5270e5 100644 --- a/astrails-safe.gemspec +++ b/astrails-safe.gemspec @@ -11,7 +11,7 @@ Gem::Specification.new do |spec| spec.description = <<-DESC Astrails-Safe is a simple tool to backup databases (MySQL and PostgreSQL), Subversion repositories (with svndump) and just files. Backups can be stored locally or remotely and can be enctypted. -Remote storage is supported on Amazon S3, Rackspace Cloud Files, or just plain SFTP. +Remote storage is supported on Amazon S3, Rackspace Cloud Files, or just plain FTP/SFTP. DESC spec.summary = %Q{Backup filesystem and databases (MySQL and PostgreSQL) locally or to a remote server/service (with encryption)} spec.homepage = "http://astrails.com/astrails-safe" diff --git a/lib/astrails/safe.rb b/lib/astrails/safe.rb index 109570a..1b0a3f8 100644 --- a/lib/astrails/safe.rb +++ b/lib/astrails/safe.rb @@ -3,6 +3,7 @@ require "aws/s3" require "cloudfiles" require 'net/sftp' +require 'net/ftp' require 'fileutils' require 'benchmark' @@ -33,6 +34,7 @@ require 'astrails/safe/s3' require 'astrails/safe/cloudfiles' require 'astrails/safe/sftp' +require 'astrails/safe/ftp' module Astrails module Safe @@ -50,7 +52,7 @@ def safe(&block) ].each do |klass, path| if collection = config[*path] collection.each do |name, c| - klass.new(name, c).backup.run(c, :gpg, :gzip, :local, :s3, :cloudfiles, :sftp) + klass.new(name, c).backup.run(c, :gpg, :gzip, :local, :s3, :cloudfiles, :sftp, :ftp) end end end diff --git a/lib/astrails/safe/config/builder.rb b/lib/astrails/safe/config/builder.rb index d979b43..400afcd 100644 --- a/lib/astrails/safe/config/builder.rb +++ b/lib/astrails/safe/config/builder.rb @@ -4,7 +4,7 @@ module Config class Builder COLLECTIONS = %w/database archive repo/ ITEMS = %w/s3 cloudfiles key secret bucket api_key container service_net path gpg password keep local mysqldump pgdump command options - user host port socket skip_tables tar files exclude filename svndump repo_path sftp/ + user host port socket skip_tables tar files exclude filename svndump repo_path sftp ftp / NAMES = COLLECTIONS + ITEMS def initialize(node) @node = node diff --git a/lib/astrails/safe/ftp.rb b/lib/astrails/safe/ftp.rb new file mode 100644 index 0000000..4f23451 --- /dev/null +++ b/lib/astrails/safe/ftp.rb @@ -0,0 +1,85 @@ +module Astrails + module Safe + class Ftp < Sink + + protected + + def active? + host && user + end + + def path + @path ||= expand(config[:ftp, :path] || config[:local, :path] || ":kind/:id") + end + + def save + raise RuntimeError, "pipe-streaming not supported for FTP." unless @backup.path + + puts "Uploading #{host}:#{full_path} via FTP" if $_VERBOSE || $DRY_RUN + + unless $DRY_RUN || $LOCAL + if !port + port = 21 + end + Net::FTP.open(host) do |ftp| + ftp.connect(host, port) + ftp.login(user, password) + puts "Sending #{@backup.path} to #{full_path}" if $_VERBOSE + begin + ftp.put(@backup.path, full_path) + rescue Net::FTPPermError + puts "Ensuring remote path (#{path}) exists" if $_VERBOSE + end + end + puts "...done" if $_VERBOSE + end + end + + def cleanup + return if $LOCAL || $DRY_RUN + + return unless keep = @config[:keep, :ftp] + + puts "listing files: #{host}:#{base}*" if $_VERBOSE + if !port + port = 21 + end + Net::FTP.open(host) do |ftp| + ftp.connect(host, port) + ftp.login(user, password) + files = ftp.nlst(path) + pattern = File.basename("#{base}") + files = files.reject{ |x| !x.start_with?(pattern)} + puts files.collect {|x| x} if $_VERBOSE + + files = files. + collect {|x| x }. + sort + + cleanup_with_limit(files, keep) do |f| + file = File.join(path, f) + puts "removing ftp file #{host}:#{file}" if $DRY_RUN || $_VERBOSE + ftp.delete(file) unless $DRY_RUN || $LOCAL + end + end + end + + def host + @config[:ftp, :host] + end + + def user + @config[:ftp, :user] + end + + def password + @config[:ftp, :password] + end + + def port + @config[:ftp, :port] + end + + end + end +end \ No newline at end of file diff --git a/templates/script.rb b/templates/script.rb index b5b1f3e..c975358 100644 --- a/templates/script.rb +++ b/templates/script.rb @@ -46,6 +46,15 @@ # path ":kind/:id" # this is the default # end + ## uncomment to enable uploads via FTP + # ftp do + # host "YOUR_REMOTE_HOSTNAME" + # user "YOUR_REMOTE_USERNAME" + # # port "NON STANDARD FTP PORT" + # password "YOUR_REMOTE_PASSWORD" + # path ":kind/:id" # this is the default + # end + ## uncomment to enable GPG encryption. ## Note: you can use public 'key' or symmetric password but not both! # gpg do