ey_cloud_server 1.4.54 → 1.4.58
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.
- checksums.yaml +8 -8
- data/bin/eyrestore +182 -0
- data/lib/ey_cloud_server/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
!binary "U0hBMQ==":
|
|
3
3
|
metadata.gz: !binary |-
|
|
4
|
-
|
|
4
|
+
ZTRlYTdlMDYxN2UzYzI2MTNjM2Y1NGMzMmFjNmJkMWQzOTVkYWU4Mg==
|
|
5
5
|
data.tar.gz: !binary |-
|
|
6
|
-
|
|
6
|
+
MGQ4M2EwYWVhMmY2OGU0ZGUxYmNhNDdkODdiMjBmN2MwNjdlZDRkZA==
|
|
7
7
|
SHA512:
|
|
8
8
|
metadata.gz: !binary |-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
N2M0ZGUzOWJhNDRlYTNiMzIxYzQ4YzcwZDY1MGI0OTY2NTVkZDQxZTA4YmQ2
|
|
10
|
+
OGY5NmUwNTg4ZDFiM2ZjMjNlNmExMjBmMWJhNjFhNGUxYTVlYzhmODlhYjc0
|
|
11
|
+
M2E2N2M5MWJjZDRlZWE3MGM2MDdkNGJlNDkzMjA2MGIxMDBkZjM=
|
|
12
12
|
data.tar.gz: !binary |-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
Mzc1YTczYzU1M2QyODA2NDgwZjE0MzJmNTVmOGEzOGZlNzJjYTc5NGRmYmEz
|
|
14
|
+
OWZjNjc0NjEyYWVhM2JkOGQxMmFkZTE0NWViNWQ2MDBlYzVjZGVmZTZkZTc2
|
|
15
|
+
NzgwYTI2NjcwZmQ0NWUwOWVmOTlkNTM3NjM2MzMxYjBlMGE4OTI=
|
data/bin/eyrestore
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'optparse'
|
|
4
|
+
require 'yaml'
|
|
5
|
+
require 'tempfile'
|
|
6
|
+
require 'timeout'
|
|
7
|
+
|
|
8
|
+
def opt_parse(argv)
|
|
9
|
+
options = {}
|
|
10
|
+
optparse = OptionParser.new do |opts|
|
|
11
|
+
opts.banner = "Usage: #{__FILE__} --env <environment name> --database <database_name> --action <action> [options]"
|
|
12
|
+
opts.separator ''
|
|
13
|
+
opts.separator "Wrapper for eybackup used for listing, downloading and restoring database backups. The main purpose for this tool is to"
|
|
14
|
+
opts.separator "simplify the process of accessing backups from one environment in a different environment (e.g. access Production backups"
|
|
15
|
+
opts.separator "from Staging). This can also be used for restoring backups within the current environment."
|
|
16
|
+
opts.separator ''
|
|
17
|
+
opts.on('-h', '--help', 'Displays this Help message') { puts opts; exit}
|
|
18
|
+
|
|
19
|
+
opts.separator ''
|
|
20
|
+
opts.separator 'Common Options:'
|
|
21
|
+
|
|
22
|
+
opts.on('-e', '--env environment_name', "Specifies the source environment name for the backups you will be working with.") { |env| options[:env] = env }
|
|
23
|
+
opts.on('-d', '--database database_name', "Name of the source database to get backups for.") { |dbname| options[:databases] = [dbname] }
|
|
24
|
+
actions=['list', 'restore', 'download']
|
|
25
|
+
opts.on('-a', '--action action_name', "The action you want to perform using the backup #{actions}.") do |action|
|
|
26
|
+
unless actions.include?(action)
|
|
27
|
+
puts "Invalid action: '#{action}' must be one of #{actions}\n\n"
|
|
28
|
+
puts opts
|
|
29
|
+
exit 1
|
|
30
|
+
end
|
|
31
|
+
options[:action] = action
|
|
32
|
+
end
|
|
33
|
+
opts.on('-i', '--index BACKUP_INDEX', 'Download/Restore the backup specified by index','BACKUP_INDEX uses the format #{index_number}:#{db_name}',
|
|
34
|
+
"The string 'last' will automatically reference the most recent available backup.") do |index|
|
|
35
|
+
options[:index] = index
|
|
36
|
+
end
|
|
37
|
+
opts.on('-f', '--force', 'Force mode, skips all confirmation prompts for use with automated restores.') { options[:force] = true }
|
|
38
|
+
|
|
39
|
+
opts.separator ''
|
|
40
|
+
opts.separator 'Additional Options:'
|
|
41
|
+
|
|
42
|
+
opts.on('-u', '--aws_secret_id key', 'AWS S3 Key') { |key| options[:aws_key_id] = key }
|
|
43
|
+
opts.on('-p', '--aws_secret_key secret', 'AWS S3 Secret Key') { |secret| options[:aws_secret_key] = secret }
|
|
44
|
+
opts.on('-b', '--backup_bucket bucket', 'AWS S3 bucket identifier') { |bucket| options[:backup_bucket] = bucket }
|
|
45
|
+
opts.on('-v', '--verbose', "Enable debug info for this wrapper.") { $verbose = true }
|
|
46
|
+
opts.on('-c', '--config', "Alternate config file for eyrestore (default ~/.eyrestore.confg.yml)") do |path|
|
|
47
|
+
unless File.exists?(path)
|
|
48
|
+
puts "Invalid config file path '#{path}', no file at that location."
|
|
49
|
+
exit 1
|
|
50
|
+
end
|
|
51
|
+
options[:def_config] = path
|
|
52
|
+
end
|
|
53
|
+
opts.separator ''
|
|
54
|
+
opts.separator 'Examples:'
|
|
55
|
+
opts.separator '* List backups from an environment named production for a database named todo'
|
|
56
|
+
opts.separator " sudo -i #{__FILE__} --env production --database todo --action list"
|
|
57
|
+
opts.separator ''
|
|
58
|
+
opts.separator '* Download the most recent backup from an environment named production for a database named todo'
|
|
59
|
+
opts.separator " sudo -i #{__FILE__} --env production --database todo --action download --index last"
|
|
60
|
+
opts.separator ''
|
|
61
|
+
opts.separator "* Download a backup from an environment named production for a database named todo, prompt with a list of available backups"
|
|
62
|
+
opts.separator " sudo -i #{__FILE__} --env production --database todo --action download"
|
|
63
|
+
opts.separator ''
|
|
64
|
+
opts.separator '* Restore the most recent backup from an environment named production for a database named todo'
|
|
65
|
+
opts.separator " sudo -i #{__FILE__} --env production --database todo --action restore --index last"
|
|
66
|
+
opts.separator ''
|
|
67
|
+
end
|
|
68
|
+
optparse.parse!
|
|
69
|
+
options
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def debug(msg)
|
|
73
|
+
puts '[' + Time.now.strftime("%D %T") + ']: DEBUG: ' + msg if $verbose
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def find_engine
|
|
77
|
+
debug("Searching for database engine based on file '/etc/.*.backups.yml'")
|
|
78
|
+
main_config = Dir['/etc/.*.backups.yml'].first
|
|
79
|
+
abort "Failed to find eybackup config at '/etc/.*.backups.yml', this needs to run on a database instance." unless main_config
|
|
80
|
+
debug("Found file '#{main_config}'")
|
|
81
|
+
File.basename(main_config).split('.')[1]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def extra_validations(options)
|
|
85
|
+
mandatory = [:databases, :env, :action]
|
|
86
|
+
missing = mandatory.select{ |param| options[param].nil? }
|
|
87
|
+
raise OptionParser::MissingArgument, missing.join(',') unless missing.empty?
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def list_backups(engine, db, path)
|
|
91
|
+
command = "eybackup -e #{engine} -l #{db} -c #{path}"
|
|
92
|
+
debug("Listing backups with command: #{command}")
|
|
93
|
+
res = %x{#{command}}
|
|
94
|
+
last = res.chomp.split("\n").last
|
|
95
|
+
abort "No Backups Found for that environment and database." if last.match(/0 backup\(s\) found/)
|
|
96
|
+
res
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def gets_timeout( prompt, secs )
|
|
100
|
+
print prompt + "[timeout=#{secs}secs]: "
|
|
101
|
+
Timeout::timeout( secs ) { gets.chomp }
|
|
102
|
+
rescue Timeout::Error
|
|
103
|
+
puts "*timeout"
|
|
104
|
+
'' # return nil if timeout
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def last_backup_idx(listing)
|
|
108
|
+
last = listing.chomp.split("\n").last
|
|
109
|
+
if last.split.first.match(/\d+:\w+/)
|
|
110
|
+
index = last.split.first
|
|
111
|
+
else
|
|
112
|
+
index = last.split[3]
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
options = opt_parse(ARGV)
|
|
117
|
+
options[:def_config] = '~/.eyrestore.config.yml' unless options[:def_config]
|
|
118
|
+
|
|
119
|
+
# auto-detect the type of database running in the given environment
|
|
120
|
+
engine = find_engine
|
|
121
|
+
|
|
122
|
+
# parse eybackup config file
|
|
123
|
+
config = YAML.load_file("/etc/.#{engine}.backups.yml")
|
|
124
|
+
this_env = config[:env]
|
|
125
|
+
# delete these just in case
|
|
126
|
+
config.delete(:env)
|
|
127
|
+
config.delete(:databases)
|
|
128
|
+
|
|
129
|
+
# override config from eyrestore config file
|
|
130
|
+
eyrestore = YAML.load_file(options[:def_config]) if File.exists?(options[:def_config])
|
|
131
|
+
config.merge!(eyrestore) unless eyrestore.nil?
|
|
132
|
+
|
|
133
|
+
# override config from command line options
|
|
134
|
+
config.merge!(options)
|
|
135
|
+
extra_validations(config)
|
|
136
|
+
debug("Config Options: '#{config}'")
|
|
137
|
+
|
|
138
|
+
# create a temporary configuration file from ~/.eyrestore.config.yml
|
|
139
|
+
temp_config = Tempfile.new("eyrestore")
|
|
140
|
+
temp_config.write(config.to_yaml)
|
|
141
|
+
temp_config.rewind
|
|
142
|
+
debug("Generated temporary config file: '#{temp_config.path}'")
|
|
143
|
+
|
|
144
|
+
db = config[:databases].first
|
|
145
|
+
temp = temp_config.path
|
|
146
|
+
if config[:action] == 'list' or ! config[:index]
|
|
147
|
+
puts list_backups(engine, db, temp)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# confirm environment overwrite if restoring
|
|
151
|
+
if config[:action] == 'restore' and ! config[:force]
|
|
152
|
+
response = gets_timeout("You are restoring the backup for '#{db}' from '#{config[:env]}' into '#{this_env}', THIS MAY BE DESTRUCTIVE; are you sure you want to proceed (Y/n) ? ", 30)
|
|
153
|
+
exit unless response.downcase == 'y'
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
if ['download','restore'].include?(config[:action])
|
|
158
|
+
config[:index] = gets_timeout("Enter the backup index to use for #{config[:action]} (e.g. 9:#{db}) ", 30) unless config[:index]
|
|
159
|
+
config[:index] = last_backup_idx(list_backups(engine, db, temp)) if config[:index] == 'last'
|
|
160
|
+
abort "Invalid backup index '#{config[:index]}'." unless config[:index].match(/^\d+:\w+$/)
|
|
161
|
+
|
|
162
|
+
action = config[:action] == 'restore' ? '-r' : '-d'
|
|
163
|
+
debug("Set action flag for eybackup to '#{action}' based on action of '#{config[:action]}'")
|
|
164
|
+
|
|
165
|
+
# test eybackup version for force option
|
|
166
|
+
ey_cloud_server_version = Gem::Version.new(%x{/usr/local/ey_resin/ruby/bin/gem list ey_cloud_server}.split[1].gsub('(','').gsub(')','').gsub(',',''))
|
|
167
|
+
force = ey_cloud_server_version >= Gem::Version.new('1.4.51') ? '--force' : ''
|
|
168
|
+
debug("eybackup version '#{ey_cloud_server_version}' so force is set to '#{force}'")
|
|
169
|
+
|
|
170
|
+
command="eybackup -e #{engine} -c #{temp} #{action} #{config[:index]} #{force}"
|
|
171
|
+
|
|
172
|
+
puts "Running '#{config[:action]}' on index '#{config[:index]}'."
|
|
173
|
+
debug("Running command: #{command}")
|
|
174
|
+
|
|
175
|
+
res=%x{#{command}}
|
|
176
|
+
puts res
|
|
177
|
+
puts "Restore complete!" if res.split("\n").last.match(/^Filename/) and config[:action] == 'restore'
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# cleanup temporary config file
|
|
181
|
+
temp_config.close
|
|
182
|
+
temp_config.unlink
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ey_cloud_server
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.4.
|
|
4
|
+
version: 1.4.58
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- EngineYard
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2017-
|
|
11
|
+
date: 2017-02-04 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: json
|
|
@@ -238,6 +238,7 @@ email:
|
|
|
238
238
|
executables:
|
|
239
239
|
- ey-snapshots
|
|
240
240
|
- eybackup
|
|
241
|
+
- eyrestore
|
|
241
242
|
extensions: []
|
|
242
243
|
extra_rdoc_files: []
|
|
243
244
|
files:
|
|
@@ -247,6 +248,7 @@ files:
|
|
|
247
248
|
- TODO
|
|
248
249
|
- bin/ey-snapshots
|
|
249
250
|
- bin/eybackup
|
|
251
|
+
- bin/eyrestore
|
|
250
252
|
- features/downloading_a_mysql_backup.feature
|
|
251
253
|
- features/making_a_postgresql_backup.feature
|
|
252
254
|
- features/restoring_postgres_backup.feature
|
|
@@ -312,7 +314,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
312
314
|
version: '0'
|
|
313
315
|
requirements: []
|
|
314
316
|
rubyforge_project:
|
|
315
|
-
rubygems_version: 2.
|
|
317
|
+
rubygems_version: 2.4.5
|
|
316
318
|
signing_key:
|
|
317
319
|
specification_version: 4
|
|
318
320
|
summary: Server side components for Engine Yard's cloud
|