sr-scripts 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in sr-scripts.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'fog'
5
+ require 'mysql'
6
+
7
+ connection = Fog::Compute.new(:provider => "AWS", :region => "us-west-1")
8
+
9
+ current_instance_id = `curl -s http://169.254.169.254/latest/meta-data/instance-id`
10
+
11
+ server = connection.servers.get(current_instance_id)
12
+
13
+ disks = server.tags["mysql_disks"].split(":")
14
+
15
+ volumes = []
16
+ server.block_device_mapping.each do |b|
17
+ if disks.include? b["deviceName"]
18
+ volumes.push b["volumeId"]
19
+ end
20
+ end
21
+
22
+ if volumes.length == 0
23
+ p "No Volumes To Snapshot"
24
+ exit
25
+ end
26
+
27
+ #check here that there aren't current pending snapshots
28
+ pending = connection.snapshots.find_all { |s| s.state == "pending" }.find_all { |s| volumes.include? s.volume_id }.length != 0
29
+ if pending
30
+ p "Exiting: Pending Snapshots Exist"
31
+ exit
32
+ end
33
+ #p "./ec2-consistent-snapshot-rb -f conf.yml #{volumes.join(' ')}"
34
+ `sr-ec2-consistent-snapshot -f /etc/sr-ec2-consistent-snapshot.yml #{volumes.join(' ')}`
@@ -0,0 +1,152 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # This script was largely ported from ec2-consistent-snapshot written
4
+ # by Eric Hammond: http://alestic.com/2009/09/ec2-consistent-snapshot
5
+ # A bunch of his features aren't ported over yet... just the stuff I needed.
6
+
7
+ require 'rubygems'
8
+ require 'optparse'
9
+ require 'fog'
10
+
11
+ $opts = {
12
+ :aws_access_key => ENV["AWS_ACCESS_KEY_ID"],
13
+ :aws_secret_access_key => ENV["AWS_SECRET_ACCESS_KEY"],
14
+ :aws_region => 'us-east-1',
15
+
16
+ :description => '',
17
+ :xfs_filesystem => nil,
18
+
19
+ :mysql => false,
20
+ :mysql_username => 'root',
21
+ :mysql_password => nil,
22
+ :mysql_host => '127.0.0.1',
23
+ :mysql_master_status_file => nil,
24
+ :mysql_slave_status_file => nil,
25
+ }
26
+
27
+ OptionParser.new do |o|
28
+ o.on("--aws-access-key ACCESS_KEY", "AWS Access Key") {|v| $opts[:aws_access_key] = v }
29
+ o.on("--aws-secret-access-key SECRET_KEY", "AWS Secret Access Key") {|v| $opts[:aws_secret_access_key] = v }
30
+ o.on("--aws-region REGION", "AWS Region") {|v| $opts[:aws_region] = v }
31
+ o.on("--description STRING", "The description for the snapshot") {|v| $opts[:description] = v }
32
+ o.on("--xfs-filesystem MOUNTPOINT", "Filesystem to be frozen during snapshot") {|v| $opts[:xfs_filesystem] = v }
33
+ o.on("--mysql", "Indicates that the volume has mysql") {|v| $opts[:mysql] = v }
34
+ o.on("--mysql-username USERNAME", "MySQL user (default: root)") {|v| $opts[:mysql_username] = v }
35
+ o.on("--mysql-password PASSWORD", "MySQL password (default: none)") {|v| $opts[:mysql_password] = v }
36
+ o.on("--mysql-host HOST", "MySQL host (default: 127.0.0.1)") {|v| $opts[:mysql_host] = v }
37
+ o.on("--mysql-master-status-file FILENAME", "File to store in snapshot with master status") {|v| $opts[:mysql_master_status_file] = v }
38
+ o.on("--mysql-slave-status-file FILENAME", "File to store in snapshot with slave status") {|v| $opts[:mysql_slave_status_file] = v }
39
+ o.on("-f", "--configfile PATH", String, "Set config file") do |path|
40
+ $opts.merge!(Hash[YAML::load(open(path)).map { |k, v| [k.to_sym, v] }])
41
+ #p Hash[YAML::load(open(path)).map { |k, v| [k.to_sym, v] }]
42
+ end
43
+ end.parse!
44
+
45
+ p $opts
46
+
47
+ if $opts[:aws_access_key].nil? || $opts[:aws_secret_access_key].nil?
48
+ puts "You must specify your Amazon credentials via --aws-access-key and --aws-secret_access-key"
49
+ exit 1
50
+ end
51
+
52
+ if ARGV.empty?
53
+ puts "You must provide at least one volume id to snapshot"
54
+ exit 1
55
+ end
56
+ volume_ids = ARGV
57
+
58
+ def mysql_locked(&block)
59
+ mysql = nil
60
+
61
+ if $opts[:mysql]
62
+ require 'mysql'
63
+ mysql = Mysql::new($opts[:mysql_host], $opts[:mysql_username], $opts[:mysql_password], nil, nil, '/mnt/mysql/mysql/mysql.sock')
64
+ mysql.query("SET SQL_LOG_BIN=0")
65
+ mysql.query("FLUSH LOCAL TABLES")
66
+ mysql.query("FLUSH LOCAL TABLES WITH READ LOCK")
67
+
68
+ def query_result_string(mysql, query)
69
+ result = mysql.query(query)
70
+ string = ""
71
+ if result.num_rows() > 0
72
+ result.fetch_row.each_with_index do |value, i|
73
+ string << "#{result.fetch_field_direct(i).name}: #{value}\n"
74
+ end
75
+ end
76
+ string
77
+ end
78
+
79
+ if $opts[:mysql_slave_status_file]
80
+ File.open($opts[:mysql_slave_status_file], "w").puts query_result_string(mysql, "SHOW SLAVE STATUS")
81
+ end
82
+
83
+ rs = mysql.query("SHOW MASTER STATUS")
84
+ if rs.num_rows() == 1
85
+ row = rs.fetch_hash
86
+ master_log_file = row["File"]
87
+ master_log_pos = row["Position"]
88
+ master_info = Hash.new
89
+ master_info["MASTER_LOG_FILE"] = master_log_file
90
+ master_info["MASTER_LOG_POS"] = master_log_pos
91
+ end
92
+ puts master_log_file
93
+
94
+ if $opts[:mysql_master_status_file]
95
+ File.open($opts[:mysql_master_status_file], "w").puts query_result_string(mysql, "SHOW MASTER STATUS")
96
+ end
97
+
98
+ mysql.query("SET SQL_LOG_BIN=1")
99
+ end
100
+
101
+ begin
102
+ yield master_info
103
+ ensure
104
+ mysql.real_query("UNLOCK TABLES") if mysql
105
+ end
106
+ end
107
+
108
+ def xfs_frozen(&block)
109
+ system('xfs_freeze', '-f', $opts[:xfs_filesystem]) if $opts[:xfs_filesystem]
110
+
111
+ begin
112
+ yield
113
+ ensure
114
+ system('xfs_freeze', '-u', $opts[:xfs_filesystem]) if $opts[:xfs_filesystem]
115
+ end
116
+ end
117
+
118
+ snapshots = []
119
+ master_info = nil
120
+
121
+ connection = Fog::Compute.new(:provider => "AWS", :aws_access_key_id => $opts[:aws_access_key], :aws_secret_access_key => $opts[:aws_secret_access_key], :region => $opts[:aws_region])
122
+ sdb = Fog::AWS::SimpleDB.new(:aws_access_key_id => $opts[:aws_access_key], :aws_secret_access_key => $opts[:aws_secret_access_key])
123
+ begin
124
+ mysql_locked() do |info|
125
+ master_info = info
126
+ xfs_frozen() do
127
+ volume_ids.each do |volume_id|
128
+ snapshot = connection.snapshots.create(:volume_id => volume_id, :description => $opts[:description])
129
+
130
+ snapshots.push(snapshot.id)
131
+ puts "#{volume_id}"
132
+ end
133
+ end
134
+ end
135
+ end
136
+
137
+ random_id = rand(36**8).to_s(36)
138
+ attributes = Hash.new
139
+ attributes["instance_id"] = `curl http://169.254.169.254/latest/meta-data/instance-id`
140
+ attributes["snapshots"] = snapshots.join(",")
141
+ attributes["timestamp"] = Time.now.to_i
142
+ attributes["master_log_file"] = master_info["MASTER_LOG_FILE"]
143
+ attributes["master_log_pos"] = master_info["MASTER_LOG_POS"]
144
+ sdb.put_attributes("db_recovery_info", random_id, attributes)
145
+
146
+ snapshots.each do |s|
147
+ attributes.each do |key, value|
148
+ connection.tags.create(:resource_id => s, :key => key, :value => value)
149
+ end
150
+ end
151
+
152
+ p master_info
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'fog'
5
+ require 'mysql'
6
+ require 'ostruct'
7
+
8
+ connection = Fog::Compute.new(:provider => "AWS", :region => "us-west-1")
9
+ sdb = Fog::AWS::SimpleDB.new()
10
+
11
+ # somewhere up here check to see if the devices are already attached
12
+
13
+ p connection.snapshots.all.first
14
+
15
+ if ARGV.length != 1
16
+ p "Must specify an instance id"
17
+ exit
18
+ end
19
+
20
+ instance_id = ARGV[0]
21
+
22
+ records = sdb.select("SELECT * FROM db_recovery_info WHERE instance_id = '#{instance_id}' AND timestamp > '1' ORDER BY timestamp DESC LIMIT 5").body["Items"]
23
+
24
+ p records
25
+
26
+ rows = []
27
+ records.each_value do |r|
28
+ r.each do |k,v|
29
+ r[k] = v[0]
30
+ end
31
+ data = OpenStruct.new(r)
32
+ rows.push data
33
+ end
34
+
35
+ rows.sort! { |a,b| b.timestamp <=> a.timestamp }
36
+
37
+ latest_snapshots = nil
38
+ rows.each do |r|
39
+ if latest_snapshots != nil
40
+ break
41
+ end
42
+ pending = false
43
+ r.snapshots.split(",").each do |snap|
44
+ if connection.snapshots.get(snap).state == "pending"
45
+ pending = true
46
+ end
47
+
48
+ end
49
+ if pending == false
50
+ latest_snapshots = r.snapshots.split(",")
51
+ end
52
+
53
+ end
54
+
55
+ #latest_snapshots now equals the snapshot ids
56
+ p latest_snapshots
57
+
58
+ def get_latest_snapshot(snapshots, instance_id)
59
+ filtered_snap = snapshots.find_all { |s| s.tags["instance_id"] == instance_id }
60
+ latest_snap = filtered_snap.sort { |a,b| b.created_at <=> a.created_at }.first unless filtered_snap.length == 0
61
+ return latest_snap
62
+ end
63
+
64
+ snapshot = get_latest_snapshot(connection.snapshots.all, instance_id)
65
+
66
+ p snapshot
67
+
68
+ # USE THE TAGS in snapshot to call CHANGE MASTER TO
69
+
70
+ current_master = connection.servers.get(instance_id)
71
+
72
+ # VALIDATE THAT NUMBER OF SNAPSHOTS EQUALS NUMBER OF MYSQL DISKS
73
+
74
+ master_disks = current_master.tags["mysql_disks"].split(":")
75
+
76
+ if latest_snapshots.length != master_disks.length
77
+ p "EXITING: Number of Snapshots != Number of Disks"
78
+ exit
79
+ end
80
+
81
+ p current_master
82
+ # need to find out the current node that this is running on
83
+ #
84
+ #
85
+ current_instance_id = `curl http://169.254.169.254/latest/meta-data/instance-id`
86
+ current_instance = connection.servers.get(current_instance_id)
87
+
88
+ latest_snapshots.each_index |index| do
89
+ snapshot_id = latest_snapshots[index]
90
+ current_disk = master_disks[index]
91
+
92
+ snapshot = connection.snapshots.get(snapshot_id)
93
+
94
+ vol = connection.volumes.new(:snapshot_id => snapshot_id, :availability_zone => current_instance.availability_zone, :size => snapshot.volume_size)
95
+ vol.device = current_disk
96
+ vol.server = current_instance
97
+ vol.save
98
+ p vol
99
+
100
+ until vol.state == "in-use" do
101
+ sleep 1
102
+ vol.reload
103
+ end
104
+ end
105
+
106
+ exit
107
+
108
+ sleep 15
109
+
110
+ # NEED TO FIND OUT IF NUMBER OF DISKS IS GREATER THAN 1, IF SO, THEN use mdadm to create an array and mount, if not, then just mount
111
+
112
+ `mkdir /mnt/mysql`
113
+ `mount -t xfs /dev/sdk /mnt/mysql`
114
+ `service mysql start`
115
+
116
+ #`mysql -e "CHANGE MASTER TO MASTER_HOST='#{current_master.private_ip_address}', MASTER_LOG_FILE='binarylogs.006693', MASTER_LOG_POS=785268118;"`
117
+ # start mysql, connect to mysql and issue change master and start slave commands
@@ -0,0 +1,5 @@
1
+ module Sr
2
+ module Scripts
3
+ VERSION = "0.0.2"
4
+ end
5
+ end
data/lib/sr-scripts.rb ADDED
@@ -0,0 +1,5 @@
1
+ module Sr
2
+ module Scripts
3
+ # Your code goes here...
4
+ end
5
+ end
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "sr-scripts/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "sr-scripts"
7
+ s.version = Sr::Scripts::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Davy Campano"]
10
+ s.email = ["dcampano@gmail.com"]
11
+ s.homepage = ""
12
+ s.summary = %q{Admin scripts}
13
+ s.description = %q{Admin scripts}
14
+
15
+ s.rubyforge_project = "sr-scripts"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sr-scripts
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 2
10
+ version: 0.0.2
11
+ platform: ruby
12
+ authors:
13
+ - Davy Campano
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-02-18 00:00:00 -06:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: Admin scripts
23
+ email:
24
+ - dcampano@gmail.com
25
+ executables:
26
+ - sr-backup-mysql
27
+ - sr-ec2-consistent-snapshot
28
+ - sr-start-slave
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - .gitignore
35
+ - Gemfile
36
+ - Rakefile
37
+ - bin/sr-backup-mysql
38
+ - bin/sr-ec2-consistent-snapshot
39
+ - bin/sr-start-slave
40
+ - lib/sr-scripts.rb
41
+ - lib/sr-scripts/version.rb
42
+ - sr-scripts.gemspec
43
+ has_rdoc: true
44
+ homepage: ""
45
+ licenses: []
46
+
47
+ post_install_message:
48
+ rdoc_options: []
49
+
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ hash: 3
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ requirements: []
71
+
72
+ rubyforge_project: sr-scripts
73
+ rubygems_version: 1.5.2
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: Admin scripts
77
+ test_files: []
78
+