class ServerBackup::BackupRestore

Constants

COMPONENTS

Public Instance Methods

run() click to toggle source
# File lib/chef/knife/backup_restore.rb, line 54
def run
  ui.warn "This will overwrite existing data!"
  ui.warn "Backup is at least 1 day old" if (Time.now - File.atime(config[:backup_dir])) > 86400
  ui.confirm "Do you want to restore backup, possibly overwriting existing data"
  validate!
  components = name_args.empty? ? COMPONENTS : name_args
  Array(components).each { |component| self.send(component) }
end

Private Instance Methods

clients() click to toggle source
# File lib/chef/knife/backup_restore.rb, line 123
def clients
  JSON.create_id = "no_thanks"
  ui.info "=== Restoring clients ==="
  clients = Dir.glob(File.join(config[:backup_dir], "clients", "*.json"))
  clients.each do |file|
    ui.info "Restoring clients from #{file}"
    client = JSON.parse(IO.read(file))
    begin
      rest.post_rest("clients", {
        :name => client['name'],
        :public_key => client['public_key'],
        :admin => client['admin'],
        :validator => client['validator']
      })
    rescue Net::HTTPServerException => e
      handle_error 'client', client['name'], e
    end
  end
end
cookbooks() click to toggle source
# File lib/chef/knife/backup_restore.rb, line 168
def cookbooks
  count = 0
  ui.info "=== Restoring cookbooks ==="
  cookbooks = Dir.glob(File.join(config[:backup_dir], "cookbooks", '*'))
  #Make tmp dir
  FileUtils.rm_rf(config[:backup_dir] + "/tmp")
  Dir.mkdir config[:backup_dir] + "/tmp"
  cookbooks.each do |cb|
    full_cb = File.expand_path(cb)
    cb_name = File.basename(cb)
    cookbook = cb_name.reverse.split('-',2).last.reverse
    full_path = File.join(config[:backup_dir] + "/tmp", cookbook)
    begin
      count += 1
      if Chef::Platform.windows?
        Dir.mkdir config[:backup_dir] + "/tmp/#{cb_name}"
        full_path = File.join(config[:backup_dir] + "/tmp/#{cb_name}", cookbook)
        ui.info "Copy cookbook #{full_cb} to #{full_path}"
        FileUtils.copy_entry(full_cb, full_path)
      else
        full_path = File.join(config[:backup_dir] + "/tmp", cookbook)
        File.symlink(full_cb, full_path)
      end
      cbu = Chef::Knife::CookbookUpload.new
      Chef::Knife::CookbookUpload.load_deps
      cbu.name_args = [ cookbook ]
      cbu.config[:cookbook_path] = File.dirname(full_path)
      ui.info "Restoring cookbook #{cbu.name_args}"
      cbu.run
    rescue Net::HTTPServerException => e
      handle_error 'cookbook', cb_name, e
    rescue Chef::Exceptions::JSON::ParseError => e
      handle_error 'cookbook', cb_name, e
      throw e unless config[:ignore_metadata_errors]
    ensure
      if Chef::Platform.windows?
        rm_path = config[:backup_dir] + "/tmp/#{cb_name}"
        ui.info "remove dir #{rm_path}"
        FileUtils.remove_dir(rm_path, force = true)
      else
        File.unlink(full_path)
      end
    end
  end
  ui.info "Uploaded #{count} Cookbooks"
  FileUtils.rm_rf(config[:backup_dir] + "/tmp")
end
data_bags() click to toggle source
# File lib/chef/knife/backup_restore.rb, line 86
def data_bags
  ui.info "=== Restoring data bags ==="
  loader = Chef::Knife::Core::ObjectLoader.new(Chef::DataBagItem, ui)
  dbags = Dir.glob(File.join(config[:backup_dir], "data_bags", '*'))
  dbags.each do |bag|
    bag_name = File.basename(bag)
    ui.info "Restoring data_bag[#{bag_name}]"
    begin
      rest.post_rest("data", { "name" => bag_name})
    rescue Net::HTTPServerException => e
      handle_error 'data_bag', bag_name, e
    end
    dbag_items = Dir.glob(File.join(bag, "*"))
    dbag_items.each do |item_path|
      item_name = File.basename(item_path, '.json')
      ui.info "Restoring data_bag_item[#{bag_name}::#{item_name}]"
      item = loader.load_from("data_bags", bag_name, item_path)
      dbag = Chef::DataBagItem.new
      dbag.data_bag(bag_name)
      dbag.raw_data = item
      dbag.save
    end
  end

end
environments() click to toggle source
# File lib/chef/knife/backup_restore.rb, line 82
def environments
  restore_standard("environments", Chef::Environment)
end
handle_error(type, name, error) click to toggle source
# File lib/chef/knife/backup_restore.rb, line 216
def handle_error(type, name, error)
  thing = "#{type}[#{name}]"
  return ui.error "Error parsing JSON for: #{thing}" if error.kind_of?(Chef::Exceptions::JSON::ParseError)

  case error.response
  when Net::HTTPConflict # 409
    ui.warn "#{thing} already exists; skipping"
  when Net::HTTPClientError # 4xx Catch All
    ui.error "Failed to create #{thing}: #{error.response}; skipping"
  else
    ui.error "Failed to create #{thing}: #{error.response}; skipping"
  end
end
nodes() click to toggle source
# File lib/chef/knife/backup_restore.rb, line 74
def nodes
  restore_standard("nodes", Chef::Node)
end
restore_standard(component, klass) click to toggle source
# File lib/chef/knife/backup_restore.rb, line 112
def restore_standard(component, klass)
  loader = Chef::Knife::Core::ObjectLoader.new(klass, ui)
  ui.info "=== Restoring #{component} ==="
  files = Dir.glob(File.join(config[:backup_dir], component, "*.json"))
  files.each do |f|
    ui.info "Restoring #{component} from #{f}"
    updated = loader.load_from(component, f)
    updated.save
  end
end
roles() click to toggle source
# File lib/chef/knife/backup_restore.rb, line 78
def roles
  restore_standard("roles", Chef::Role)
end
users() click to toggle source
# File lib/chef/knife/backup_restore.rb, line 143
def users
  JSON.create_id = "no_thanks"
  ui.info "=== Restoring users ==="
  users = Dir.glob(File.join(config[:backup_dir], "users", "*.json"))
  if !users.empty? and Chef::VERSION !~ /^11\./
    ui.warn "users restore only supported on chef == 11"
    return
  end
  users.each do |file|
    user = JSON.parse(IO.read(file))
    password = SecureRandom.hex[0..7]
    begin
      rest.post_rest("users", {
        :name => user['name'],
        :public_key => user['public_key'],
        :admin => user['admin'],
        :password => password
      })
      ui.info "Set password for #{user['name']} to #{password}, please update"
    rescue Net::HTTPServerException => e
      handle_error 'user', user['name'], e
    end
  end
end
validate!() click to toggle source
# File lib/chef/knife/backup_restore.rb, line 66
def validate!
  bad_names = name_args - COMPONENTS
  unless bad_names.empty?
    ui.error "Component types #{bad_names.join(",")} are not valid."
    exit 1
  end
end