gat 0.2.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/History.txt +84 -0
  2. data/PostInstall.txt +22 -0
  3. data/README.txt +49 -0
  4. data/Rakefile +12 -0
  5. data/bin/gat +15 -0
  6. data/lib/gat.rb +323 -0
  7. data/lib/gat/action/base.rb +197 -0
  8. data/lib/gat/action/ruby_method.rb +35 -0
  9. data/lib/gat/action/shell_command.rb +185 -0
  10. data/lib/gat/boot.rb +63 -0
  11. data/lib/gat/checks.rb +136 -0
  12. data/lib/gat/debug.rb +29 -0
  13. data/lib/gat/dependence/argument.rb +62 -0
  14. data/lib/gat/dependence/base.rb +54 -0
  15. data/lib/gat/dependence/folder.rb +104 -0
  16. data/lib/gat/dependence/program.rb +36 -0
  17. data/lib/gat/email.rb +80 -0
  18. data/lib/gat/exceptions.rb +163 -0
  19. data/lib/gat/extends.rb +102 -0
  20. data/lib/gat/help.rb +79 -0
  21. data/lib/gat/interpreter.rb +93 -0
  22. data/lib/gat/launcher.rb +100 -0
  23. data/lib/gat/logger.rb +331 -0
  24. data/lib/gat/operation.rb +253 -0
  25. data/lib/gat/version.rb +20 -0
  26. data/lib/gatgets/dar_backup/dar_backup.rb +367 -0
  27. data/lib/gatgets/dar_backup/dar_backup.yml +387 -0
  28. data/lib/gatgets/dar_backup/launcher.rb +44 -0
  29. data/lib/gatgets/dar_backup/templates/list_backups.erb +31 -0
  30. data/lib/gatgets/dar_backup/templates/search.erb +33 -0
  31. data/lib/gatgets/gatgets_manager/gatgets_manager.rb +65 -0
  32. data/lib/gatgets/gatgets_manager/gatgets_manager.yml +71 -0
  33. data/lib/gatgets/gatgets_manager/templates/list.erb +9 -0
  34. data/lib/gatgets/synchronization/README +26 -0
  35. data/lib/gatgets/synchronization/launcher.rb +20 -0
  36. data/lib/gatgets/synchronization/launcher_cron.sh +69 -0
  37. data/lib/gatgets/synchronization/synchronization.rb +123 -0
  38. data/lib/gatgets/synchronization/synchronization.yml +144 -0
  39. data/test/test_gat.rb +36 -0
  40. data/test/test_helper.rb +3 -0
  41. metadata +131 -0
data/lib/gat/checks.rb ADDED
@@ -0,0 +1,136 @@
1
+ =begin
2
+
3
+ :file => checks.rb
4
+ :author => (c) 2008-2009 A.C. Gnoxys info@gnoxys.net
5
+
6
+ ######################################################################################
7
+ ## This file is part of GAT: http://gat.rubyforge.org ##
8
+ ## ##
9
+ ## GAT (Gnoxys Administration Tools) is released under the GPL License 3 or higher. ##
10
+ ## You can get a copy of the license easily at http://www.gnu.org/licenses/gpl.html.##
11
+ ######################################################################################
12
+
13
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
14
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
17
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
18
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+
21
+ =end
22
+
23
+ module Gat
24
+
25
+ # Gat::Checks Module
26
+ #
27
+ # Check methods return true or false through some arguments. Extend module if you want to add more checkable methods
28
+ #
29
+ # Check methods are hash based to better human arguments readeable. I mean, when you make a comparation beetwen two
30
+ # values, it is better to use arguments[:small] > arguments[:big] thatn arguments[0] > arguments[1]
31
+ #
32
+ # So, need_arguments method is avaible as public inside this module. This function will check the arguments hash
33
+ # and raise a GatgetConfixException if check_method miss one argument. For example
34
+ #
35
+ # def check_minor_than(arguments)
36
+ # need_arguments(['minor', 'major'], arguments)
37
+ # arguments['minor'] < arguments['major']
38
+ # end
39
+ #
40
+ # check_minor_than('minor' => 10, 'bigger' => 20) # => raise GatgetConfigException
41
+ # check_minor_than('minor' => 10, 'major' => 20) # => true
42
+ # check_minor_than('minor' => 20, 'major' => 10) # => false
43
+ module Checks
44
+
45
+ # Files checkers!!!!!!
46
+ # --------------------
47
+
48
+ # Check if file exist
49
+ def check_file_exists(arguments)
50
+ need_arguments(['file_url'], arguments)
51
+ File.exists?(arguments['file_url'])
52
+ end
53
+
54
+ # Check if file exist
55
+ def check_file_not_exists(arguments)
56
+ need_arguments(['file_url'], arguments)
57
+ !File.exists?(arguments['file_url'])
58
+ end
59
+
60
+ def check_enough_space(arguments)
61
+ need_arguments(['where', 'space_needed'], arguments)
62
+ # get space at where
63
+ space = %x[ df -B 1 #{ arguments['where'] }].split("\n").last.split(" ")[3].to_i
64
+ space > arguments['space_needed'].to_i
65
+ end
66
+
67
+ def check_true(arguments)
68
+ need_arguments(['true_expression'], arguments)
69
+ eval("#{ arguments['true_expression'] }")
70
+ end
71
+
72
+ def check_false(arguments)
73
+ need_arguments(['false_expression'], arguments)
74
+ !eval(arguments['false_expression'])
75
+ end
76
+
77
+
78
+
79
+ # need_arguments checks that all the needed arguments are in array
80
+ # raise GagetConfigException if someone is not avaliable
81
+ def need_arguments(needed, avalaible)
82
+ needed.each do |need|
83
+ unless avalaible.keys.include?(need)
84
+ raise GatgetConfigException.new("needed argument #{ need } not avalaible at #{ self.class.name }", "need_arguments")
85
+ end
86
+ end
87
+ end
88
+
89
+ def exit_if_i_am_running(myname = nil)
90
+ if check_i_am_running(myname)
91
+ exit 0
92
+ end
93
+ end
94
+
95
+ def check_i_am_running(myname = nil)
96
+ # lock dirs/files
97
+ myname ||= File.basename($0, ".rb")
98
+ lockdir="/tmp/#{myname}-lock"
99
+ pidfile="#{lockdir}/PID"
100
+
101
+ ### start locking attempt
102
+
103
+ r = FileUtils.mkdir(lockdir) rescue r = nil
104
+ if not r.nil?
105
+ # lock succeeded, install signal handlers and store the PID
106
+ trap 0, proc { p "Trapped"
107
+ FileUtils.rm_rf lockdir }
108
+ r = File.open(pidfile, 'w') {|f| f.write($$) }
109
+ else
110
+ # lock failed, now check if the other PID is alive
111
+ begin
112
+ f = File.open(pidfile, 'r')
113
+ otherpid = f.readline.to_i
114
+ rescue
115
+ # if it wasn't possible to read the file anymore, another instance probably is
116
+ # about to remove the lock -- exit, we're *still* locked
117
+ return true
118
+ end
119
+ r = Process.kill(0, otherpid) rescue r = nil
120
+ if r == nil
121
+ # lock is stale, remove it and go on
122
+ trap 0, proc { p "Trapped"
123
+ FileUtils.rm_rf lockdir }
124
+ r = File.open(pidfile, 'w') {|f| f.write($$) } rescue r=nil
125
+ return false
126
+ else
127
+ # lock is valid and otherpid is active - exit, we're locked!
128
+ return true
129
+ end
130
+ end
131
+ return false
132
+ end
133
+
134
+
135
+ end
136
+ end
data/lib/gat/debug.rb ADDED
@@ -0,0 +1,29 @@
1
+ =begin
2
+ This file is part of GAT: http://gat.rubyforge.org
3
+
4
+ (c) 2008-2009 A.C. Gnoxys info@gnoxys.net
5
+
6
+ GAT (Gnoxys Administration Tools) is released under the GPL License 3 or higher.
7
+ You can get a copy of the license easily at http://www.gnu.org/licenses/gpl.html.
8
+
9
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
10
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
11
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
13
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
14
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
15
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16
+ =end
17
+
18
+ module Gat
19
+ module Debug
20
+
21
+ def print_debug_msg(message)
22
+ $stdout.puts "* debug *: #{ message } \n"
23
+ end
24
+
25
+ def get_debug_levels
26
+ { "trace" => 4, "message" => 3, "warning" => 2, "error" => 1, "direct_output" => 0 }
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,62 @@
1
+ module Gat
2
+ module Dependence
3
+ class Argument < Base
4
+
5
+ attr_reader :position
6
+ attr_reader :optional
7
+ attr_reader :prefix
8
+ attr_reader :type
9
+
10
+ attr :value
11
+
12
+ def initialize(name, config, operation)
13
+
14
+ super(name, config, operation)
15
+ # by default, argument is command line
16
+ @type = @config['type'] || 'command_line'
17
+ @optional = @config['optional'] || false
18
+ @prefix = @config['prefix'] || nil
19
+
20
+ @@argument_position ||= 0
21
+ @position = ( @@argument_position += 1 )
22
+
23
+ end
24
+
25
+ # Argument must come
26
+ def evalue
27
+ # command line arguments
28
+ if self.type == 'command_line' and self.operation.gatget.arguments.any? and self.operation.gatget.arguments[self.position]
29
+
30
+ # ToDo => add prefix to arguments
31
+ # if self.position == 'prefix'
32
+ #prefix_position = self.operation.gatget.arguments.index(self.prefix)
33
+ #self.value = self.operation.gatget.arguments[
34
+ # else
35
+ self.value = self.operation.gatget.arguments[self.position]
36
+ # end
37
+
38
+ # get arguments
39
+ elsif self.type == 'get' or self.type == 'get_password'
40
+
41
+ # log direct question
42
+ get_question = self.config['get_question'] || "Gatget need a value for argument #{ self.name } (#{ self.description })"
43
+
44
+ self.operation.gatget.logger.log("direct", 'get_argument', get_question)
45
+
46
+ system "stty -echo" if self.type == 'get_password' # remove letter echo
47
+
48
+ self.value = $stdin.gets.chomp
49
+
50
+ system "stty echo" if self.type == 'get_password' # remove letter echo
51
+
52
+ # argument missing but not required
53
+ elsif self.optional
54
+ self.operation.gatget.logger.log("info", "missing argument #{ self.name } at operation #{ self.operation.name }. Argument is marked as optional")
55
+ else
56
+ raise GatgetArgumentException.new("Missing dependence argument #{ self.name } (@#{ self.type}) ", "evalue_program_dependence")
57
+ end
58
+ end
59
+
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,54 @@
1
+ =begin
2
+
3
+ :file => dependences.rb
4
+ :author => (c) 2008-2009 A.C. Gnoxys info@gnoxys.net
5
+
6
+ ######################################################################################
7
+ ## This file is part of GAT: http://gat.rubyforge.org ##
8
+ ## ##
9
+ ## GAT (Gnoxys Administration Tools) is released under the GPL License 3 or higher. ##
10
+ ## You can get a copy of the license easily at http://www.gnu.org/licenses/gpl.html.##
11
+ ######################################################################################
12
+
13
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
14
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
17
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
18
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+
21
+ =end
22
+
23
+
24
+ module Gat
25
+ module Dependence
26
+ class Base
27
+
28
+ attr_reader :operation
29
+ attr_reader :config
30
+ attr_reader :name
31
+ attr_reader :type
32
+ attr_reader :description
33
+
34
+
35
+ attr_accessor :value
36
+
37
+
38
+ def initialize(name, config, operation)
39
+ operation.gatget.logger.log("trace", "dependence", "Initialize dependence #{ self.class } @#{ name }")
40
+ @operation = operation
41
+ @config = config
42
+ @name = name
43
+ @description = @config['description'] || "Another #{ self.class } dependence named #{ self.name }"
44
+ end
45
+
46
+
47
+ def evalue
48
+ raise GatgetException.new("Evalue method is not available at Gat::Dependece. Create your own at #{ self.class }", 'evalue_dependence_without_type')
49
+ end
50
+
51
+ end
52
+ end
53
+ end
54
+
@@ -0,0 +1,104 @@
1
+ module Gat
2
+ module Dependence
3
+ class Folder < Base
4
+
5
+ attr_reader :value
6
+ attr_reader :path
7
+ attr_reader :config
8
+ attr_reader :mode
9
+
10
+ attr :tree
11
+
12
+ def initialize(name, config, operation)
13
+ super(name, config, operation)
14
+ @type = config['type'] || 'normal'
15
+ @tree = { }
16
+ @path = config['path'] || ''
17
+ @mode = config['mode'] || 0700
18
+ end
19
+
20
+ # Folders
21
+ def evalue
22
+ if self.path.blank?
23
+ raise GatgetConfigException.new("folder #{ self.name } doesnt have a path attribute at config", 'evalue_folder_dependence')
24
+ end
25
+
26
+ # mount directory
27
+ mounted? if self.type == 'mount'
28
+
29
+ # main folder
30
+ unless File.exists?(self.path) and File.directory?(self.path)
31
+ FileUtils.mkdir_p(self.path, :mode => self.mode)
32
+ end
33
+
34
+ # tree
35
+ if self.config['tree'] and self.config['tree'].any?
36
+ self.config['tree'].each do |subfolder|
37
+ absolut_folder = "#{ self.path }/#{ subfolder }"
38
+ unless File.exists?(absolut_folder) and File.directory?(absolut_folder)
39
+ FileUtils.mkdir_p(absolut_folder, :mode => self.mode)
40
+ end
41
+ self.tree["#{ self.name }_#{ subfolder.gsub(/\//,'_') }"] = absolut_folder
42
+ end
43
+ end
44
+ end
45
+
46
+ # Folder dependence value is special, because it can be the root folder or one subfolder at tree
47
+ # so, we dont have a value attribute but method, and this method check by folder_name, which folder do we want
48
+ def value(folder_name)
49
+ ret = ''
50
+ if folder_name == self.name
51
+ ret = self.path
52
+ elsif self.tree.any?
53
+ self.tree.each_pair do |subfolder_name, subfolder_path|
54
+ ret = subfolder_path if subfolder_name == folder_name
55
+ end
56
+ end
57
+
58
+ if ret.blank?
59
+ raise GatgetException.new("Value for folder dependence #{ folder_name } doesnt return results", "value_folders_dependence")
60
+ end
61
+ ret
62
+ end
63
+
64
+ private
65
+ # check if folder is mounted, if not, try it, if doesnt work, launch GatgetProcessException
66
+ def mounted?
67
+ unless already_mounted?
68
+ unless mount_folder
69
+ raise Gat::GatgetProcessException.new("Unable to mount folder #{ self.name } at #{ self.path }", "mounted")
70
+ end
71
+ end
72
+ end
73
+
74
+
75
+ # Open Unix mounts folder and test that mounts table contents main folder
76
+ def already_mounted?
77
+ mounts_file = File.open('/proc/mounts', 'r')
78
+ mounted = false
79
+ mounts_file.each_line do |mount_line|
80
+ mounted = true if mount_line.split(" ")[2].include?(self.path)
81
+ end
82
+ mounted
83
+ end
84
+
85
+
86
+ def mount_folder
87
+ self.operation.gatget.logger.log("trace", "mount_folder", "Folder #{ self.name } is not mounted. Triying to mount")
88
+
89
+ pid_open4, stdin, stdout, stderr = Open4::popen4 "mount #{ self.path }"
90
+
91
+ ignored, status_open4 = Process::waitpid2 pid_open4
92
+
93
+ if status_open4.exitstatus == 0 # try to mount_folder
94
+ self.operation.gatget.logger.log("trace", "mount_folder", "Folder #{ self.name } nicely mounted ")
95
+ ret = true
96
+ else
97
+ self.operation.gatget.logger.log("error", "mount_folder", "#{ stderr.read }")
98
+ ret = false
99
+ end
100
+ ret
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,36 @@
1
+ module Gat
2
+ module Dependence
3
+ class Program < Base
4
+
5
+ attr_reader :path
6
+
7
+ def initialize(name, config, operation)
8
+ super(name, config, operation)
9
+ @type = @config['type'] || 'external'
10
+ @path = @config['path'] || false
11
+ end
12
+
13
+ def evalue
14
+ self.path || evalue_from_shell
15
+ end
16
+
17
+ # Program is evalued through 'which' shell command
18
+ def evalue_from_shell
19
+ errors = ''
20
+ output = ''
21
+ process_id = ''
22
+ status = Open4.popen4 "which #{ self.name }" do |pid, stdin, stdout, stderr|
23
+ process_id = pid
24
+ errors = stderr.readlines.join('')
25
+ output = stdout.readlines.join('')
26
+ end
27
+
28
+ if not output.blank? and errors.blank? and status.exitstatus == 0
29
+ self.value = output.strip
30
+ else
31
+ raise GatgetConfigException.new("Dependece program #{ self.name } not found", "evalue_program_dependence")
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
data/lib/gat/email.rb ADDED
@@ -0,0 +1,80 @@
1
+ =begin
2
+ This file is part of GAT: http://gat.rubyforge.org
3
+
4
+ (c) 2008-2009 A.C. Gnoxys info@gnoxys.net
5
+
6
+ GAT (Gnoxys Administration Tools) is released under the GPL License 3 or higher.
7
+ You can get a copy of the license easily at http://www.gnu.org/licenses/gpl.html.
8
+
9
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
10
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
11
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
13
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
14
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
15
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16
+ =end
17
+
18
+ module Gat
19
+ module Email
20
+
21
+ # Create and deliver a email
22
+ def create_and_deliver_email(to, email_config, deliver_config)
23
+ email = new_email(to, deliver_config.merge(email_config))
24
+ send_email(email, deliver_config)
25
+ end
26
+
27
+
28
+ def send_email(email, smtp_config)
29
+
30
+ if !smtp_config or smtp_config.empty? or !smtp_config['send_by']
31
+ raise GatgetConfigException.new('email_config is empty or missing or send_by is not defined', 'send_email')
32
+ end
33
+
34
+ domain = self.config['server_domain'] || 'localhost'
35
+ email_from = smtp_config["send_from"] || "#{ self.class.name }@#{ domain }"
36
+
37
+
38
+ case smtp_config['send_by']
39
+ when 'smtp'
40
+ server = smtp_config['smtp_config']["server"] || 'localhost'
41
+ port = smtp_config['smtp_config']["port"] || 25
42
+ user = smtp_config['smtp_config']["user"] || ""
43
+ password = smtp_config['smtp_config']["password"] || ""
44
+
45
+ begin
46
+ Net::SMTP.start(server, port, server, user, password, :login) do |smtp|
47
+ smtp.send_mail email.encoded, email_from, email.destinations
48
+ end
49
+ rescue => error
50
+ raise GatgetConfigException.new(error, "send_email(smtp)",
51
+ { :message => "Error sending mail to '#{email.destinations}' on '#{server}:#{port}': #{error}" })
52
+ end
53
+
54
+ when 'sendmail'
55
+
56
+ Net::SMTP.start('localhost', 25) do |smtp|
57
+ smtp.send_mail email.encoded, email_from, email.destinations
58
+ end
59
+
60
+ else
61
+ raise GatgetConfigException.new("undefined send_mail method #{ smtp_config['send_by'] } at config", 'send_email')
62
+ end
63
+ end
64
+
65
+ def new_email(to, options = {})
66
+
67
+ options ||= Hash.new
68
+ mail = TMail::Mail.new
69
+ mail.date = Time.now
70
+ mail.to = to
71
+ mail.subject = options['subject'] || "#{ self.class.name } email report"
72
+ mail.from = options['send_from'] || "#{ self.class.name.underscore }@#{ self.config['server_name'] }"
73
+ mail.cc = options['cc'] if options['cc']
74
+ mail.bcc = options['bcc'] if options['bcc']
75
+
76
+ mail.body = options['body'] || "empty body"
77
+ mail
78
+ end
79
+ end
80
+ end