Compare commits
No commits in common. "58b6de55a24f62484e699f9356559db15dd73319" and "f433321fb832af174cd34a6de32d0e2605f7ded8" have entirely different histories.
58b6de55a2
...
f433321fb8
263
bucket-tool
263
bucket-tool
@ -1,10 +1,5 @@
|
|||||||
#!/usr/bin/ruby
|
#!/usr/bin/ruby
|
||||||
|
|
||||||
# BEGIN: Requires
|
|
||||||
|
|
||||||
require 'digest'
|
|
||||||
|
|
||||||
# END: Requires
|
|
||||||
|
|
||||||
# BEGIN: Helper Functions
|
# BEGIN: Helper Functions
|
||||||
|
|
||||||
@ -19,24 +14,15 @@ Description:
|
|||||||
search the filebucket and restore from it.
|
search the filebucket and restore from it.
|
||||||
|
|
||||||
Actions:
|
Actions:
|
||||||
search <term> : Search for bucket entries matching a portion of the filepath
|
search <term> : Search for bucket entries matching a portion of the filepath
|
||||||
list : List all Bucket entries
|
list : List all Bucket entries
|
||||||
list-files : List all files/paths that have been backed up to the bucket
|
list-files : List all files/paths that have been backed up to the bucket
|
||||||
get <entry-hash> : Get the content of a specific entry (by hash)
|
get <entry-hash> : Get the content of a specific entry (by hash)
|
||||||
restore <value> : Restore previous state of file stored in bucket. Value can be hash or filename/filepath
|
restore <entry-hash> : Restore previous state of file stored in bucket (by-hash)
|
||||||
|
|
||||||
Global Flags:
|
Global Flags:
|
||||||
-d | --debug : Set debug flag
|
-d | --debug : Set debug flag
|
||||||
-h | --help : This help message
|
-h | --help : This help message
|
||||||
|
|
||||||
Info Format Flags:
|
|
||||||
-i | --inline : Set the info format to inline (MTIME : HASH : FILENAME)
|
|
||||||
-l | --long : Set the info format to long
|
|
||||||
: Entry [HASH]:
|
|
||||||
: Paths: path1,path2,...,pathn
|
|
||||||
: MTIME: YYYY-MM-DD HH:MM:SS -####
|
|
||||||
:
|
|
||||||
-c | --csv : Set the info format to csv ( MTIME,HASH,FILENAME1[;FILENAMEn] )
|
|
||||||
|
|
||||||
Author:
|
Author:
|
||||||
Name: Tristan Ancelet
|
Name: Tristan Ancelet
|
||||||
@ -76,18 +62,6 @@ def log (message, level = 0)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def which(cmd)
|
|
||||||
#https://stackoverflow.com/questions/2108727/which-in-ruby-checking-if-program-exists-in-path-from-ruby
|
|
||||||
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
|
||||||
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
|
||||||
exts.each do |ext|
|
|
||||||
exe = File.join(path, "#{cmd}#{ext}")
|
|
||||||
return exe if File.executable?(exe) && !File.directory?(exe)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_verification (prompt = "Do you want to continue?")
|
def get_verification (prompt = "Do you want to continue?")
|
||||||
while true
|
while true
|
||||||
puts "#{prompt} (y/n): "
|
puts "#{prompt} (y/n): "
|
||||||
@ -104,54 +78,6 @@ def get_verification (prompt = "Do you want to continue?")
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_selections (reference_array, prompt = "Which of the following do you want to select? ", options = { :multiple => false, }, &procedure)
|
|
||||||
## Making clone of array since the selections were passed by reference
|
|
||||||
selections = reference_array.clone
|
|
||||||
|
|
||||||
def put_prompt (selections, prompt)
|
|
||||||
puts prompt
|
|
||||||
selections.each_with_index do |value,index|
|
|
||||||
puts "#{index} : #{value}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if options[:multiple] == true
|
|
||||||
output = Array.new
|
|
||||||
else
|
|
||||||
output = ""
|
|
||||||
end
|
|
||||||
|
|
||||||
put_prompt selections, prompt
|
|
||||||
|
|
||||||
while true
|
|
||||||
choice = Integer(STDIN.gets.strip())
|
|
||||||
if choice.is_a? Integer
|
|
||||||
if choice >= 0 and choice < selections.count
|
|
||||||
if options[:multiple] == true
|
|
||||||
output.push(selections[choice])
|
|
||||||
selections.delete_at(choice)
|
|
||||||
if get_verification "Are you done selecting?"
|
|
||||||
break
|
|
||||||
end
|
|
||||||
put_prompt selections, prompt
|
|
||||||
else
|
|
||||||
output = selections[choice]
|
|
||||||
break
|
|
||||||
end
|
|
||||||
else
|
|
||||||
puts "#{choice} is not between the values of 0 and #{selections.count}. Please try again."
|
|
||||||
end
|
|
||||||
else
|
|
||||||
puts "#{choice} is not a valid option. Please try again."
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if procedure.respond_to? "call"
|
|
||||||
output = procedure.call(output)
|
|
||||||
end
|
|
||||||
output
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# END: Helper Functions
|
# END: Helper Functions
|
||||||
|
|
||||||
|
|
||||||
@ -171,19 +97,11 @@ end
|
|||||||
|
|
||||||
$DEBUG=false
|
$DEBUG=false
|
||||||
|
|
||||||
puppet_exe = which "puppet"
|
|
||||||
|
|
||||||
if puppet_exe == nil
|
|
||||||
puts "The puppet utility was not found in $PATH. This utility will not be able to function"
|
|
||||||
exit
|
|
||||||
end
|
|
||||||
|
|
||||||
$CONFIG = Hash.new
|
$CONFIG = Hash.new
|
||||||
$CONFIG[:bucket_dir]=` #{puppet_exe} agent --configprint clientbucketdir `.strip()
|
$CONFIG[:bucket_dir]=` puppet agent --configprint clientbucketdir `.strip()
|
||||||
$CONFIG[:action]=""
|
$CONFIG[:action]=""
|
||||||
$CONFIG[:search_term]=""
|
$CONFIG[:search_term]=""
|
||||||
$CONFIG[:log_file]=""
|
$CONFIG[:log_file]=""
|
||||||
$CONFIG[:info_format]="inline"
|
|
||||||
File.open('/etc/hostname') do |file|
|
File.open('/etc/hostname') do |file|
|
||||||
$HOSTNAME=file.read().strip()
|
$HOSTNAME=file.read().strip()
|
||||||
end
|
end
|
||||||
@ -232,25 +150,6 @@ case ARGV[i]
|
|||||||
exit
|
exit
|
||||||
end
|
end
|
||||||
|
|
||||||
while i < ARGV.count
|
|
||||||
case ARGV[i]
|
|
||||||
when '-c', '--csv'
|
|
||||||
$CONFIG[:info_format]='csv'
|
|
||||||
log "$CONFIG[:info_format] was set to #{$CONFIG[:info_format]}"
|
|
||||||
i+=1
|
|
||||||
when '-l', '--long'
|
|
||||||
$CONFIG[:info_format]='long'
|
|
||||||
log "$CONFIG[:info_format] was set to #{$CONFIG[:info_format]}"
|
|
||||||
i+=1
|
|
||||||
when '-i', '--inline'
|
|
||||||
$CONFIG[:info_format]='inline'
|
|
||||||
log "$CONFIG[:info_format] was set to #{$CONFIG[:info_format]}"
|
|
||||||
i+=1
|
|
||||||
else
|
|
||||||
i+=1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
## BEGIN: Checks
|
## BEGIN: Checks
|
||||||
|
|
||||||
if $CONFIG[:action] == ""
|
if $CONFIG[:action] == ""
|
||||||
@ -264,7 +163,6 @@ case $CONFIG[:action]
|
|||||||
usage
|
usage
|
||||||
exit
|
exit
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
## END: Checks
|
## END: Checks
|
||||||
@ -279,8 +177,12 @@ class BucketEntry
|
|||||||
def initialize (entry_dir)
|
def initialize (entry_dir)
|
||||||
@entry_dir = entry_dir
|
@entry_dir = entry_dir
|
||||||
@hash = File.basename(entry_dir)
|
@hash = File.basename(entry_dir)
|
||||||
|
@filepaths = Array.new
|
||||||
File.open("#{entry_dir}/paths") do |file|
|
File.open("#{entry_dir}/paths") do |file|
|
||||||
@filepaths = file.read.split(/\n/)
|
file.read().split(/\n/).each do |path|
|
||||||
|
log "BucketEntry[#{@hash}] adding #{path} to @filepaths"
|
||||||
|
@filepaths.push(path)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
@mtime = File.mtime(entry_dir)
|
@mtime = File.mtime(entry_dir)
|
||||||
log "BucketEntry was created from #{entry_dir}"
|
log "BucketEntry was created from #{entry_dir}"
|
||||||
@ -288,10 +190,10 @@ class BucketEntry
|
|||||||
|
|
||||||
def path_include? (path_string)
|
def path_include? (path_string)
|
||||||
log "BucketEntry[#{hash}] was called with #{path_string}"
|
log "BucketEntry[#{hash}] was called with #{path_string}"
|
||||||
@filepaths.any?{|path| path.include? path_string}
|
@filepaths.each.any? {|path| path.include? path_string}
|
||||||
end
|
end
|
||||||
|
|
||||||
def long_info
|
def infostring
|
||||||
"Entry [#{@hash}]:
|
"Entry [#{@hash}]:
|
||||||
Paths: #{@filepaths.join(',')}
|
Paths: #{@filepaths.join(',')}
|
||||||
MTIME: #{@mtime}
|
MTIME: #{@mtime}
|
||||||
@ -299,25 +201,10 @@ class BucketEntry
|
|||||||
"
|
"
|
||||||
end
|
end
|
||||||
|
|
||||||
def csv_info
|
|
||||||
[@mtime,@hash,@filepaths.join(';')].join(',')
|
|
||||||
end
|
|
||||||
|
|
||||||
def inline_info
|
def inline_info
|
||||||
"#{@mtime} : #{@hash} : #{@filepaths.join(',')}"
|
"#{@mtime} : #{@hash} : #{@filepaths.join(',')}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def info
|
|
||||||
case $CONFIG[:info_format]
|
|
||||||
when 'long'
|
|
||||||
long_info
|
|
||||||
when 'inline'
|
|
||||||
inline_info
|
|
||||||
when 'csv'
|
|
||||||
csv_info
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def content
|
def content
|
||||||
log "BucketEntry[#{@hash}] getting contents"
|
log "BucketEntry[#{@hash}] getting contents"
|
||||||
File.open("#{@entry_dir}/contents",'r') do |file|
|
File.open("#{@entry_dir}/contents",'r') do |file|
|
||||||
@ -336,15 +223,6 @@ class Bucket
|
|||||||
load_bucket
|
load_bucket
|
||||||
end
|
end
|
||||||
|
|
||||||
def select(&proc)
|
|
||||||
@entries.each_value.select &proc
|
|
||||||
end
|
|
||||||
|
|
||||||
def any?(&proc)
|
|
||||||
@entries.each_value.any? &proc
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
def load_bucket
|
def load_bucket
|
||||||
log "Bucket[#{@bucketdir}] is loading entries"
|
log "Bucket[#{@bucketdir}] is loading entries"
|
||||||
Dir["#{@bucketdir}/**/paths"].each.map{|path| File.dirname(path)}.each do |directory|
|
Dir["#{@bucketdir}/**/paths"].each.map{|path| File.dirname(path)}.each do |directory|
|
||||||
@ -355,18 +233,6 @@ class Bucket
|
|||||||
end
|
end
|
||||||
log "Bucket[#{@bucketdir}] was loaded"
|
log "Bucket[#{@bucketdir}] was loaded"
|
||||||
end
|
end
|
||||||
|
|
||||||
def filenames
|
|
||||||
filenames = Array.new
|
|
||||||
@entries.each_value do |entry|
|
|
||||||
entry.filepaths.each do |path|
|
|
||||||
if not filenames.include? path
|
|
||||||
filenames.push(path)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
filenames
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# END: Classes
|
# END: Classes
|
||||||
@ -376,10 +242,17 @@ end
|
|||||||
# BEGIN: Work Functions
|
# BEGIN: Work Functions
|
||||||
|
|
||||||
def search_entries_paths (bucket)
|
def search_entries_paths (bucket)
|
||||||
puts bucket.select{|entry| entry.path_include? $CONFIG[:search_term]}.sort_by(&:mtime).map(&:info)
|
log "user entered"
|
||||||
|
bucket.entries.each_value do |entry|
|
||||||
|
log "checking Entry[#{entry.hash}]"
|
||||||
|
if entry.path_include? $CONFIG[:search_term]
|
||||||
|
puts entry.inline_info
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_content_of_entry_hash (bucket)
|
def get_content_of_entry_hash (bucket)
|
||||||
|
log "user entered"
|
||||||
if bucket.entries.has_key? $CONFIG[:search_term]
|
if bucket.entries.has_key? $CONFIG[:search_term]
|
||||||
puts bucket.entries[$CONFIG[:search_term]].content
|
puts bucket.entries[$CONFIG[:search_term]].content
|
||||||
else
|
else
|
||||||
@ -389,84 +262,40 @@ def get_content_of_entry_hash (bucket)
|
|||||||
end
|
end
|
||||||
|
|
||||||
def list_all_entries (bucket)
|
def list_all_entries (bucket)
|
||||||
puts bucket.filenames.map{|filename| bucket.select{|entry| entry.path_include? filename}.sort_by(&:mtime).map(&:info)}
|
puts bucket.entries.each_value.each.map{|entry| entry.inline_info}.sort.join("\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
def list_entry_files (bucket)
|
def list_entry_files (bucket)
|
||||||
puts bucket.filenames.sort.join("\n")
|
filenames = Array.new
|
||||||
end
|
bucket.entries.each_value do |entry|
|
||||||
|
entry.filepaths.each do |path|
|
||||||
def get_entry_by_file (bucket, filenames)
|
if not filenames.include? path
|
||||||
entry = nil
|
filenames.push(path)
|
||||||
if filenames.count == 1
|
|
||||||
filename = filenames[0]
|
|
||||||
else
|
|
||||||
filename = get_selections filenames, "Your filename matched multiple files. Please select one to restore"
|
|
||||||
end
|
|
||||||
|
|
||||||
entries = bucket.select{|entry| entry.path_include? filename}
|
|
||||||
if entries.count == 1
|
|
||||||
entry = entries.first
|
|
||||||
else
|
|
||||||
while true
|
|
||||||
mtimes = entries.map{|entry| entry.mtime}
|
|
||||||
entry_mtime = get_selections(mtimes , "Which timestamp to you want to revert the file to?")
|
|
||||||
entry = entries.lazy.select{|entry| entry.mtime == entry_mtime}.first
|
|
||||||
|
|
||||||
if get_verification "Do you want to see the contents of #{filename} at this time?"
|
|
||||||
puts entry.content
|
|
||||||
if get_verification "Is this the entry you want to overwrite #{filename} with?"
|
|
||||||
break
|
|
||||||
end
|
|
||||||
else
|
|
||||||
break
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
puts filenames.sort.join("\n")
|
||||||
if filename[0] != '/'
|
|
||||||
filename = "/#{filename}"
|
|
||||||
end
|
|
||||||
|
|
||||||
return entry, filename
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_entry_by_hash (bucket)
|
|
||||||
if bucket.entries.has_key? $CONFIG[:search_term]
|
|
||||||
entry = bucket.entries[$CONFIG[:search_term]]
|
|
||||||
filepath = ""
|
|
||||||
if entry.filepaths.count == 1
|
|
||||||
filepath = entry.filepaths[0]
|
|
||||||
else
|
|
||||||
filepath = get_selections entry.filepaths, "What filepath do you wish to restore to?"
|
|
||||||
end
|
|
||||||
|
|
||||||
if filepath[0] != '/'
|
|
||||||
filepath = "/#{filepath}"
|
|
||||||
end
|
|
||||||
|
|
||||||
return entry, filepath
|
|
||||||
|
|
||||||
else
|
|
||||||
puts "There were no entries corresponding to #{$CONFIG[:search_term]}"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def restore_entry (bucket)
|
def restore_entry (bucket)
|
||||||
entry = nil
|
if bucket.entries.has_key? $CONFIG[:search_term]
|
||||||
if bucket.any?{ |entry| entry.path_include? $CONFIG[:search_term] }
|
entry = bucket.entries[$CONFIG[:search_term]]
|
||||||
filenames = bucket.filenames.select {|filename| filename.include? $CONFIG[:search_term]}
|
if entry.filepaths.count == 1
|
||||||
entry, filepath = get_entry_by_file bucket, filenames
|
filepath = entry.filepaths[0]
|
||||||
else
|
if filepath[0] != '/'
|
||||||
entry, filepath = get_entry_by_hash bucket
|
filepath = "/#{filepath}"
|
||||||
end
|
end
|
||||||
|
if get_verification "Are you sure you want to overwrite #{filepath}?"
|
||||||
if get_verification "Are you sure you want to overwrite #{filepath}?"
|
File.open(filepath,'w') do |file|
|
||||||
File.open(filepath,'w') do |file|
|
file.write(entry.content)
|
||||||
file.write(entry.content)
|
end
|
||||||
|
else
|
||||||
|
puts "Ok not overwriting."
|
||||||
|
end
|
||||||
|
else
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
puts "Ok not overwriting."
|
puts "There were no entries corresponding to #{$CONFIG[:search_term]}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user