Created
August 23, 2012 14:13
-
-
Save langalex/3437036 to your computer and use it in GitHub Desktop.
Couchbase EBS RAID Backup on Scalarium
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# Backs up the mounted EBS RAID storage used by Couchbase of an EC2 instance using the Scalarium API. | |
# | |
# Before running the snapshot it stops Couchbase disk writes and then freezes the file system. | |
# File system must be XFS. | |
# | |
# Usage: Backup.new(<scalarium api token>, <mount point for ebs raid>, <name of couchbase bucket to back up>).start (must be run on the EC2 instance). | |
require 'rest_client' | |
require 'json' | |
require 'timeout' | |
class Backup | |
def initialize(api_token, mount_point, couch_bucket_name) | |
@headers = {'X-Scalarium-Token' => api_token, | |
'Accept' => 'application/vnd.scalarium-v1+json'} | |
@mount_point = mount_point | |
@couch_bucket_name = couch_bucket_name | |
end | |
def start | |
begin | |
puts "Instance #{instance_id}" | |
puts "Stopping bucket" | |
run "/opt/couchbase/bin/cbflushctl 127.0.0.1:11210 stop #{couch_bucket_name}" | |
puts "Waiting for bucket to flush data" | |
print '.' while !bucket_flushed? | |
puts | |
puts "Freezing file system" | |
run "xfs_freeze -f #{mount_point}" | |
instance_volumes.each do |v| | |
create_snapshot(v['id']) | |
end | |
puts 'Waiting for snapshots to complete' | |
Timeout::timeout(60 * 60) do | |
wait_for_completion | |
end | |
rescue => e | |
STDERR.puts e.message | |
exit(1) | |
ensure | |
puts "Unfreezing file system" | |
run "xfs_freeze -u #{mount_point}" | |
puts "Restarting bucket" | |
run "/opt/couchbase/bin/cbflushctl 127.0.0.1:11210 start #{couch_bucket_name}" | |
end | |
end | |
private | |
attr_reader :headers, :couch_bucket_name, :mount_point | |
def instance_volumes | |
@instance_volumes ||= api_get('/volumes').map{|v| v.select{|k, v| | |
%w(instance_id name id raid_array_id).include?(k)}}.select{|v| | |
v['raid_array_id']}.group_by{|v| v['instance_id']}[instance_id] | |
end | |
def instance_id | |
@instance_id ||= JSON.parse(File.read('/var/lib/scalarium/cluster_state.json'))['instance']['id'] | |
end | |
def url(path) | |
"https://manage.scalarium.com/api#{path}" | |
end | |
def run(cmd) | |
`#{cmd}` | |
unless $?.success? | |
puts "FAILED\n" | |
end | |
end | |
def api_get(path) | |
retry_count = 0 | |
begin | |
JSON.parse(RestClient.get(url(path), headers).body) | |
rescue RestClient::InternalServerError => e | |
retry_count += 1 | |
sleep 2 | |
if retry_count < 5 | |
retry | |
else | |
raise e | |
end | |
end | |
end | |
def create_snapshot(volume_id) | |
puts "Snapshotting #{volume_id}" | |
res = RestClient.post url("/volumes/#{volume_id}/snapshot"), '', headers | |
if res.code != 201 | |
puts 'FAILED' | |
puts res.body | |
puts | |
end | |
end | |
def bucket_flushed? | |
`/opt/couchbase/bin/cbstats 127.0.0.1:11210 all -b #{@couch_bucket_name} | grep ep_uncommitted | awk '{print $2}'`.strip == '0' | |
end | |
def wait_for_completion | |
begin | |
progress = [] | |
completed = instance_volumes.reduce(true) do |result, v| | |
snapshot = api_get("/volumes/#{v['id']}/snapshots").first | |
progress << snapshot['progress'].to_i | |
result && snapshot['status'] == 'completed' | |
end | |
print "#{progress.reduce(:+) / progress.size.to_f}% ... " | |
sleep 5 | |
end while !completed | |
end | |
end | |
t = Time.now | |
Backup.new('<scalarium api token>', '<mount point>' , '<couch bucket>').start | |
puts "Backup took #{Time.now - t}s" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment