dantswain
dantswain

Reputation: 5467

Ruby backup gem - shared configurations?

I'm using meskyanichi's backup gem. By and large it does what I need it to, but I need to have multiple backups (e.g., hourly, daily, weekly). The configurations are mostly the same but have a few differences, so I need to have multiple configuration files. I'm having trouble finding a sane way to manage the common bits of configurations (i.e., not repeat the common parts).

The configuration files use a lot of block structures, and from what I can tell, each backup needs to have a separate config file (e.g. config/backup/hourly.rb, config/backup/daily.rb, etc). A typical config file looks like this:

Backup::Model.new(:my_backup, 'My Backup') do

  database MySQL do |db|
    db.name               = "my_database"
    db.username           = "foo"
    db.password           = "bar"
    # etc
  end

  # similar for other config options

end

Then the backup is executed a la bundle exec backup perform -t my_backup -c path/to/config.rb.

My first swag at enabling a common config was to define methods that I could call from the blocks:

def my_db_config db
  db.name = "my_database"
  # etc
end

Backup::Model.new(:my_backup, 'My Backup') do
  database MySQL do |db|
    my_db_config db
  end
  #etc
end

But this fails with an undefined method 'my_db_config' for #<Backup::Database::MySQL:0x10155adf0>.

My intention was to get this to work and then split the common config functions into another file that I could require in each of my config files. I also tried creating a file with the config code and requireing it into the model definition block:

# common.rb
database MySQL do |db|
  db.name = "my_database"
  #etc
end

# config.rb
Backup::Model.new(:my_backup, 'My Backup') do
  require "common.rb" # with the right path, etc
end

This also doesn't work, and from subsequent research I've discovered that that's just not the way that require works. Something more in line with the way that C/C++'s #include works (i.e., blindly pasting the contents into whatever scope it is called from) might work.

Any ideas?

Upvotes: 5

Views: 1315

Answers (2)

Yevgeniy Shchemelev
Yevgeniy Shchemelev

Reputation: 3651

In newest versions of backup gem you can simple use main config file like this:

Genrate main config file:

root@youhost:~# backup generate:config

Modify file /root/Backup/config.rb like this:

Backup::Storage::S3.defaults do |s3|
  s3.access_key_id     = "youkey"
  s3.secret_access_key = "yousecret"
  s3.region            = "us-east-1"
  s3.bucket            = "youbacket"
  s3.path              = "youpath"
end

Backup::Database::PostgreSQL.defaults do |db|
      db.name               = "youname"
      db.username           = "youusername"
      db.password           = "youpassword"
      db.host               = "localhost"
      db.port               = 5432
      db.additional_options = ["-xc", "-E=utf8"]
end

Dir[File.join(File.dirname(Config.config_file), "models", "*.rb")].each do |model|
  instance_eval(File.read(model))
end

Create model file:

root@youhost:~# backup generate:model --trigger daily_backup \
--databases="postgresql" --storages="s3"

Then modify /root/Backup/models/daily_backup.rb like this:

# encoding: utf-8

Backup::Model.new(:daily_backup, 'Description for daily_backup') do
  split_into_chunks_of 250

  database PostgreSQL do |db|
    db.keep = 20
  end

  store_with S3 do |s3|
    s3.keep = 20
  end

end

With this you can simply create daily, monthly or yearly archives.

Upvotes: 1

Benoit Garret
Benoit Garret

Reputation: 13675

The gem seems to modify the execution scope of the config blocks. To work around this, you could wrap your functions in a class:

class MyConfig
  def self.prepare_db(db)
    db.name = "my_database"
    # etc
    db
  end
end

Backup::Model.new(:my_backup, 'My Backup') do
  database MySQL do |db|
    db = MyConfig.prepare_db(db)
  end
  #etc
end

You could get a bit more fancy and abstract your default config merge:

class BaseConfig
  @@default_sets = 
    :db => {
      :name => "my_database"
    },
    :s3 => {
      :access_key => "my_s3_key"
    }
  }

  def self.merge_defaults(initial_set, set_name)
    @@default_sets[set_name].each do |k, v|
      initial_set.send("#{k}=".to_sym, v)
    end
    initial_set
  end
end

Backup::Model.new(:my_backup, 'My Backup') do
  database MySQL do |db|
    db = BaseConfig.merge_defaults(db, :db)
  end

  store_with S3 do |s3|
    s3 = BaseConfig.merge_defaults(s3, :s3)
  end
end

Upvotes: 2

Related Questions