sr-scripts 0.0.2

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/.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
+