mongo-ec2-backup 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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