mongo-ec2-backup 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -2,67 +2,38 @@
2
2
 
3
3
  Suite of tools to backup and manage snapshots of MongoDB data set to EC2 Snapshots.
4
4
 
5
- ## Lock and Snapshot: lock_and_snapshot.rb
5
+ ## Lock and Snapshot: mongo_lock_and_snapshot.rb
6
6
 
7
7
  ### Usage
8
8
 
9
- Snapshot a list of devices on a given instance on ec2. Requires network access in order to lock and unlock Mongo
9
+ Snapshot a list of devices on a given instance on ec2.
10
10
 
11
11
  ```shell
12
- ./lock_and_snapshot.rb -a ACCESS_KEY_ID -s SECRET_ACCESS_KEY --hostname server01 --devices /dev/sdl,/dev/slm --type daily --limit 4
12
+ /mnt/lib/mongo-ec2-consistent-backup/bin# infra-ruby lock_and_snapshot -p /ebs/lvms/lvol0/ -a ACCESS_KEY -s SECRET_KEY -d /dev/sdg,/dev/sdh,/dev/sdi,/dev/sdj,/dev/sdk,/dev/sdl,/dev/sdm,/dev/sdn
13
13
  ```
14
14
 
15
- * --port, -p <i>: Mongo port to connect to (default: 27017)
16
- * --access-key-id, -a <s>: Access Key Id for AWS
17
- * --secret-access-key, -s <s>: Secret Access Key for AWS
18
- * --devices, -d <s>: Devices to snapshot, comma separated
19
- * --hostname, -h <s>: Hostname to look for. Should resolve to a local EC2 Ip
20
- * --type, -t <s>: Snapshot type, to choose among snapshot,weekly,monthly,daily,yearly (default: snapshot)
21
- * --limit, -l <i>: Cleanup old snapshots to keep only limit snapshots. Default values are stored in EC2VolumeSnapshoter::KIND
22
- * --region: Region hosting the instances
23
- * --help, -e: Show this message
15
+ * --path, -p : Data path to freeze
16
+ * --access-key-id, -a : Access Key Id for AWS
17
+ * --secret-access-key, -s : Secret Access Key for AWS
18
+ * --devices, -d : Devices to snapshot, comma separated
19
+ * --type, -t : Snapshot type, to choose among test,snapshot,daily,weekly,monthly,yearly (default: snapshot)
20
+ * --help, -h: Show this message
24
21
 
25
- ### Usage in chef environment
22
+ It freeze the path using ```xfs_freeze```and create a snapshot for all the disks passed in the command line. To make this work without too much trouble with a mongo that is in a replica set, you can shut down the replica before running the command. You can also use mongo fsync and lock but this will probably make your cluster a bit nervous about that. Shutting down ensure no mongos will try to use the frozen mongo.
26
23
 
27
- In order to run the command from a remote server (the Chef server or any administrative node of your grid), you need to be able to know the lists of the devices you wish to snapshot.
24
+ ### Usage with IAM
28
25
 
29
- By using the ohai-raid plugin (https://github.com/octplane/ohai-raid), Chef clients can fill part of their Chef registry with information about the software managed RAID arrays running.
30
- This information can be fetched out for use at a later point via the knife script provided in the ohai-raid package:
26
+ If you use IAM for your authentication in EC2, here is a probably up to date list of the permissions you need to grant:
31
27
 
32
28
  ```
33
- knife exec scripts/show_raid_devices server01.fqdn.com /dev/md0
34
- /dev/sdl,/dev/sdm,/dev/sdn,/dev/sdo
29
+ "ec2:CreateSnapshot",
30
+ "ec2:DeleteSnapshot",
31
+ "ec2:DescribeSnapshots",
32
+ "ec2:CreateTags",
33
+ "ec2:DescribeTags",
34
+ "ec2:DescribeVolumes",
35
+ "ec2:DescribeInstances",
36
+ "ec2:AttachVolume",
37
+ "ec2:CreateVolume"
35
38
  ```
36
-
37
- You can combine the two tools to automate daily backup of you MongoDB server:
38
-
39
- ```
40
- ./lock_and_snapshot.rb -a ACCESS_KEY_ID -s SECRET_ACCESS_KEY --hostname server01 --devices $(knife exec /path/to/scripts/show_raid_devices server01.fqdn.com /dev/md0) --type daily
41
- ```
42
-
43
- ### Tool Description
44
-
45
- * Find instance id by resolving the hostname provided in the CLI and scanning the instances in EC2
46
- * Lock Mongo by connecting via the hostname:port provided in the parameters
47
- * Snapshot the disks, delete old backups
48
- * Unlock Mongo
49
-
50
- ## MD inspection: ec2-consistent-backup.rb
51
-
52
- ### Usage
53
-
54
- This script demonstrates the way it analyses Mongo DB Data path to extract the MD device and components associated
55
-
56
- ```shell
57
- ./ec2-consistent-backup -p 27017
58
- ```
59
-
60
- ### Tool description
61
-
62
- * connect to mongo at port provided, retrieves dbpath
63
- * find what mount this dbpath corresponds to
64
- * use /proc/mdstat to find out which drive are corresponding to the dbpath mount disk
65
-
66
- # API
67
-
68
39
  Internal API documentation is at: http://rubydoc.info/github/octplane/mongo-ec2-consistent-backup/master/frames
data/Rakefile CHANGED
@@ -3,12 +3,12 @@ require "rake/clean"
3
3
  require 'rake/gempackagetask'
4
4
  require 'rake/rdoctask'
5
5
 
6
- desc "Packages up Swissr."
6
+ desc "Packages up the gem."
7
7
  task :default => :package
8
8
 
9
9
  spec = Gem::Specification.new do |s|
10
10
  s.name = 'mongo-ec2-backup'
11
- s.version = '0.0.4'
11
+ s.version = '0.0.5'
12
12
  s.summary = 'Snapshot your mongodb in the EC2 cloud via XFS Freeze'
13
13
 
14
14
  s.author = 'Pierre Baillet'
@@ -25,6 +25,7 @@ spec = Gem::Specification.new do |s|
25
25
  s.files = FileList['lib/**/*.rb', 'bin/*', '[A-Z]*', 'test/**/*'].to_a
26
26
 
27
27
  s.executables << "mongo_lock_and_snapshot"
28
+ s.executables << "ec2_snapshot_restorer"
28
29
 
29
30
  # Supress the warning about no rubyforge project
30
31
  s.rubyforge_project = 'nowarning'
@@ -0,0 +1,132 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ ENV['BUNDLE_GEMFILE'] = File.join(File.dirname(__FILE__), "..", "Gemfile")
5
+ require 'bundler/setup'
6
+ require 'trollop'
7
+ require 'fog'
8
+ require 'open-uri'
9
+
10
+ $: << File.join(File.dirname(__FILE__), "../lib")
11
+
12
+ DEBUG=false
13
+
14
+ def log what
15
+ puts what if DEBUG
16
+ end
17
+ #
18
+ class SnapshotRestorer
19
+ attr_accessor :snaps
20
+ def initialize(aki, sak)
21
+ @compute = Fog::Compute.new({:provider => 'AWS', :aws_access_key_id => aki, :aws_secret_access_key => sak})
22
+ @snaps = []
23
+ @volumes = []
24
+ end
25
+ def find_snapshots(instance_id, kind = 'snapshot')
26
+ log "Looking for snapshots for #{instance_id}"
27
+ volume_map = []
28
+ snapshots = {}
29
+
30
+ tags = @compute.tags.all(:key => 'instance_id', :value => instance_id)
31
+
32
+ max_date = nil
33
+ tags.each do |tag|
34
+ snap = @compute.snapshots.get(tag.resource_id)
35
+ t = snap.tags
36
+
37
+ # Ignore in progress snapshots
38
+ if instance_id == t['instance_id'] &&
39
+ snap.state == 'completed' &&
40
+ t['kind'] == kind
41
+ max_date = t['date'] if !max_date || max_date < t['date']
42
+ log "#{snap.inspect} is valid"
43
+ snapshots[t['date']] ||= []
44
+ snapshots[t['date']] << snap
45
+ end
46
+ end
47
+ snapshots['LATEST'] = snapshots[max_date] if snapshots[max_date]
48
+ return snapshots
49
+ end
50
+ def prepare_volumes(dest_instance)
51
+ @snaps.each do | resource_id |
52
+ snap = @compute.snapshots.get(resource_id)
53
+ # Snap have the following tags
54
+ # application
55
+ # device
56
+ # instance_id
57
+ # date
58
+ # kind
59
+
60
+ t = snap.tags
61
+ volume = @compute.volumes.new :snapshot_id => snap.id, :size => snap.volume_size, :availability_zone => 'us-east-1c'
62
+ volume.save
63
+ volume.reload
64
+ @compute.create_tags(volume.id, { "application" => t['application'],
65
+ "sdevice" => t['device'],
66
+ "date" => t['date'],
67
+ "kind" => t['kind'],
68
+ "sinstance" => t['instance_id'],
69
+ "dinstance" => dest_instance})
70
+
71
+ @volumes << volume
72
+ end
73
+ def rattach_volumes(base_device = nil)
74
+ dest = base_device
75
+ if !dest
76
+ dest = @volumes.map{ |v| v.tags['sdevice']}.min
77
+ end
78
+ dest = dest.dup
79
+
80
+ @volumes.each do |vol|
81
+ vol.reload
82
+ puts "Attaching #{vol.id} to #{dest} on #{vol.tags['dinstance']}"
83
+ @compute.attach_volume(vol.tags['dinstance'], vol.id, dest)
84
+ dest.next!
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ if __FILE__ == $0
91
+ require 'trollop'
92
+ require 'ec2_instance_identifier'
93
+ require 'pp'
94
+ opts = Trollop::options do
95
+ opt :hostname, "Hostname tag to use to find the instance", :type => :string, :required => true
96
+ opt :access_key_id, "Access Key Id for AWS", :type => :string, :required => true
97
+ opt :secret_access_key, "Secret Access Key for AWS", :type => :string, :required => true
98
+ opt :date, "Date to restore, use LATEST to take latest data", :type => :string
99
+ opt :type, "Snapshot type to restore, defaults to snapshot", :type => :string, :default => 'snapshot'
100
+ opt :target, "Creates volume ready for mounting on instance id. Use special value SELF to restore here", :type => :string
101
+ opt :first_device, "First device to attach to (default is to use source first device) /dev/sdx", :type => :string
102
+ end
103
+
104
+ finder = EC2InstanceIdentifier.new(opts[:access_key_id], opts[:secret_access_key])
105
+ instance_identifier = finder.get_instance(opts[:hostname]).id
106
+ s = SnapshotRestorer.new(opts[:access_key_id], opts[:secret_access_key])
107
+
108
+ # Find this instance snapshots
109
+ snaps = s.find_snapshots(instance_identifier, opts[:type])
110
+
111
+ if ! opts[:date] || !snaps.has_key?(opts[:date])
112
+ puts "We have found the following snapshot's dates:"
113
+ snaps.each do |k,v|
114
+ puts "- #{k} (#{v.length} volume snapshots)"
115
+ end
116
+ else
117
+ puts "Snapshot taken at #{opts[:date]}"
118
+ snaps[opts[:date]].each do |snapshot|
119
+ puts "- #{snapshot.id}, #{snapshot.volume_size}GB - #{snapshot.tags['device']}"
120
+ end
121
+ if opts[:target]
122
+ s.snaps = snaps[opts[:date]].map{ |s| s.id }
123
+ target = opts[:target]
124
+ target = open("http://169.254.169.254/latest/meta-data/instance-id").read if target == "SELF"
125
+ puts "Preparing volumes for instance #{target}"
126
+ s.prepare_volumes(target)
127
+ # Need to clone, because trollop freeze the variable
128
+ s.rattach_volumes(opts[:first_device])
129
+ end
130
+ end
131
+
132
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongo-ec2-backup
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-06 00:00:00.000000000 Z
12
+ date: 2012-09-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: fog
@@ -79,13 +79,14 @@ description:
79
79
  email: oct@fotopedia.com
80
80
  executables:
81
81
  - mongo_lock_and_snapshot
82
+ - ec2_snapshot_restorer
82
83
  extensions: []
83
84
  extra_rdoc_files: []
84
85
  files:
85
86
  - lib/ec2-consistent-backup.rb
86
87
  - lib/ec2_instance_identifier.rb
87
- - lib/ec2_snapshot_restorer.rb
88
88
  - lib/ec2_volume_snapshoter.rb
89
+ - bin/ec2_snapshot_restorer
89
90
  - bin/mongo_lock_and_snapshot
90
91
  - Gemfile
91
92
  - Gemfile.lock
@@ -1,34 +0,0 @@
1
- require 'fog'
2
- require 'open-uri'
3
-
4
-
5
- #
6
- class SnapshotRestorer
7
- def initialize(aki, sak, snap_ids)
8
- @compute = Fog::Compute.new({:provider => 'AWS', :aws_access_key_id => aki, :aws_secret_access_key => sak})
9
- @snaps = snap_ids
10
- @volumes = []
11
- end
12
- def restore()
13
- @snaps.each do | resource_id |
14
- snap = @compute.snapshots.get(resource_id)
15
- # Snap have the following tags
16
- # application
17
- # device
18
- # instance_id
19
- # date
20
- # kind
21
-
22
- t = snap.tags
23
- volume = @compute.volumes.new :snapshot_id => snap.id, :size => snap.volume_size, :availability_zone => 'us-east-1c'
24
- @compute.tags.create(:resource_id => volume.id, :key =>"application", :value => NAME_PREFIX)
25
- @compute.tags.create(:resource_id => volume.id, :key =>"device", :value => device)
26
- @compute.tags.create(:resource_id => volume.id, :key =>"date", :value => ts)
27
- @compute.tags.create(:resource_id => volume.id, :key =>"kind", :value => kind)
28
- volume.save
29
- @volumes << volume
30
- end
31
- end
32
- def connect(instance_id = open("http://169.254.169.254/latest/meta-data/instance-id").read)
33
- end
34
- end