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
@@ -0,0 +1,197 @@
1
+ =begin
2
+
3
+ :file => action/base.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
+
25
+ module Gat
26
+
27
+
28
+ # Gat::Action::Base
29
+ #
30
+ # Action are pieces of operations. Actions are the objetives of dependences
31
+ # Actions have the next config options at YML definition
32
+ #
33
+ # <action_name> *must be uniq*
34
+ # type: <shell_command> || <ruby_method>
35
+ # Type of the action. It can be
36
+ # - shell_command: Action will execute a shell command
37
+ # - ruby_method: Action will call a ruby_method called by action.name
38
+ # flags: [ <action flags> ]
39
+ # Conditional flags have to been passed to execute action. Action is skipped if only one flag failed
40
+ # Flags can be marked as negative. For example, [ '!file_doesnt_exist' ]. In this case, flags must be marked as false
41
+ # to result in action execution
42
+ #
43
+ # syntax: "<shell_command_syntax">
44
+ # Only in Shell Commands types, syntax is the command line form to be executed by Ruby Terminal.
45
+ #
46
+ # multiple: ["<n multiple parameters>"]
47
+ # Only in shell commands types.
48
+ # If multiple isnt empty, Action will interprete multiple parameters as multiple values. That means, that gat expect
49
+ # that multiple paramters return an array of values. Gat::Action will loop and execute each shell_command with these parameters substitions
50
+ # For example, that is usefull to exec one command peer each File in one Dir.
51
+ #
52
+ # onfail: "<continue> || <abort>"
53
+ # What happens is action end with non 0 status
54
+ #
55
+ # onfail_message: "<onfail_message>"
56
+ # Custom message to be logged at error
57
+ #
58
+ # onfail_callback: "<on_fail_callback>"
59
+ # Custom ruby method that is executed if action fails
60
+
61
+ module Action
62
+
63
+ class Base
64
+
65
+ include Gat::Interpreter
66
+
67
+ attr_reader :operation
68
+ attr_reader :config
69
+ attr_reader :name
70
+ attr_reader :argument
71
+ attr_reader :description
72
+ attr_reader :flags
73
+ attr_accessor :error
74
+
75
+
76
+ attr_accessor :times
77
+ attr_accessor :output
78
+ attr_accessor :errors
79
+ attr_accessor :exit_level
80
+
81
+ attr_accessor :status
82
+
83
+ attr_accessor :parsed_syntax
84
+
85
+ attr_accessor :onfail
86
+ attr_accessor :onfail_message
87
+ attr_accessor :onfail_callback
88
+
89
+
90
+
91
+ # Get the current action
92
+ def self.get_current_action
93
+ @@current_action
94
+ end
95
+
96
+
97
+ def initialize(name, config, operation)
98
+
99
+ operation.gatget.logger.log("trace", "action", "Initialize action #{ self.class } @#{ name }")
100
+
101
+ @times = Hash.new
102
+ @times['init'] = Time.now
103
+ @operation = operation
104
+ @config = config
105
+ @name = name
106
+ @description = config['description'] || "Another Action named #{ name }"
107
+ @flags = config['flags'] || [ ]
108
+ @output = ''
109
+ @error = nil
110
+
111
+ @onfail = config['onfail'] || 'abort'
112
+ @onfail_message = config['onfail_message']
113
+ @onfail_callback = config['onfail_callback']
114
+
115
+ @@current_action = self
116
+ end
117
+
118
+
119
+ def execute
120
+
121
+ if self.execute?
122
+
123
+ self.run
124
+
125
+ #self.set_outputs
126
+
127
+ unless self.exit_level == 0
128
+ self.operation.gatget.logger.log("warning", "action_error", "#{self.error}")
129
+ self.operation.gatget.logger.log("warning", "action_error", "Action #{ self.name } finished with status #{self.exit_level}")
130
+
131
+ if self.onfail_callback
132
+ self.operation.gatget.send(self.onfail_callback)
133
+ end
134
+
135
+ if self.onfail == 'abort'
136
+ self.operation.gatget.logger.log('error', 'action_execute', "Action #{ self.name } abort Gatget")
137
+ self.operation.status = 'fail'
138
+
139
+ raise GatgetProcessException.new(self.error, "execute_action", self.onfail_message ? {:message => self.onfail_message} : {} )
140
+ end
141
+ end
142
+
143
+ end
144
+
145
+ @times['end'] = Time.now
146
+ end
147
+
148
+
149
+ # Execute? Method check if action must be executed. It test the follow conditions
150
+ # If flags is set, check that all flags are true
151
+ # If operation state is to abort or skip actions, skip actions
152
+ def execute?
153
+ flags_ok? and status_ok?
154
+ end
155
+
156
+
157
+ private
158
+ # Check if action flags are ok...
159
+ def flags_ok?
160
+ flags_ok = true
161
+ marker_flag = nil
162
+
163
+ if @flags and @flags.any?
164
+ @flags.each do |flag|
165
+
166
+ if flag[0..0] == '!'
167
+ compare_with = false
168
+ flag = flag.gsub(/^!/,'')
169
+ else
170
+ compare_with = true
171
+ end
172
+
173
+ unless self.operation.gatget.get_flag(flag) == compare_with
174
+ flags_ok = false
175
+ marker_flag = flag
176
+ end
177
+ end
178
+ end
179
+
180
+ unless flags_ok
181
+ self.operation.gatget.logger.log("message", "action", "Action #{ self.class } @#{ self.name } not mark to exec by flag: #{ marker_flag }")
182
+ end
183
+ flags_ok
184
+ end
185
+
186
+ def status_ok?
187
+ status_ok = self.operation.status == 'ok'
188
+ unless status_ok
189
+ self.operation.gatget.logger.log("message", "action", "Operation #{ self.operation.name } is not marked as OK. Actions are skipped")
190
+ end
191
+ status_ok
192
+ end
193
+
194
+ end
195
+
196
+ end
197
+ end
@@ -0,0 +1,35 @@
1
+
2
+ module Gat
3
+ module Action
4
+ class RubyMethod < Base
5
+
6
+ attr_accessor :status
7
+
8
+ def run
9
+
10
+ self.exec
11
+
12
+ end
13
+
14
+
15
+ def exec
16
+ self.operation.gatget.logger.log("trace", "action_syntax", "Action #{ self.name } exec ruby method." )
17
+ self.times['init'] ||= Time.now
18
+
19
+ begin
20
+ self.operation.gatget.send(self.name)
21
+ self.status = 'ok'
22
+ self.exit_level = 0
23
+ rescue => e
24
+ self.error = e
25
+ self.status = 'failed'
26
+ self.exit_level = 1
27
+ end
28
+
29
+ self.times['end'] ||= Time.now
30
+ self.exit_level
31
+ end
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,185 @@
1
+ module Gat
2
+ module Action
3
+
4
+ class ShellCommand < Base
5
+
6
+ attr_reader :syntax
7
+ attr_reader :childs
8
+ attr_accessor :arguments
9
+
10
+ attr_accessor :pid
11
+ attr_accessor :status
12
+
13
+ def initialize(name, config, operation)
14
+ super(name, config, operation)
15
+
16
+ @syntax = config['syntax'] || raise(GatgetConfigException.new("Shell Command Action #{ name } has not a syntax attribute", "initialize_shell_command"))
17
+ end
18
+
19
+
20
+ def run
21
+ ret = nil
22
+ # Shell Command can be multiple, that means the command will be execute over a foreach variable subtitutions.
23
+ # That is usefull, for example, when you need to do the same actions with some variable subtition, like
24
+ # a multiple files compression.
25
+ @childs = (@config['multiple'] and @config['multiple'].any?) ? set_multiple_childs(@config['multiple']) : [ ]
26
+
27
+ # If ShellCommand is multiple, then, we exec all of its childs
28
+ # If not, we just execute ShellCommand instance
29
+ if @childs.any?
30
+ @childs.each { |child|
31
+ if not child.exec
32
+ ret = false
33
+ end
34
+ }
35
+ else
36
+ self.parsed_syntax = interpreter_parameters(self.syntax, self.operation.gatget)
37
+ ret = exec(self.parsed_syntax)
38
+ end
39
+
40
+ if self.config['output']
41
+ self.operation.gatget.logger.log("direct", "action_output", self.output)
42
+ end
43
+ ret
44
+ end
45
+
46
+
47
+ # Execute shell command with Open4
48
+ #
49
+ # Open4 module is the next generation Ruby module for executing shell commands.
50
+ # Open4 works better thant the standard Open3 module, and has built inside the feature
51
+ # to return exit status through Process.status Class.
52
+ # Even it has some problems too. Open4 module has big problems when the stdout or the stderr comes
53
+ # with tons of information. For example, with a mysqldump output.
54
+ #
55
+ # The solution presented here is a wapper through Process.fork. We create a new fork, making
56
+ # and the output is not managed by the ruby script itself but by the fork process.
57
+ # IO.pipes are created to pass the stdout, stderr and stdin data through Gat proccess and Fork process
58
+ #
59
+ # Some disccusion about this can be readed here: http://stackoverflow.com/questions/1076257/returning-data-from-forked-processes
60
+ #
61
+ # Maybe, we could use Theread.new, and maybe it would be better, but... =)
62
+ #
63
+ def exec(shell_command, multiple_name = '')
64
+
65
+ trap_save = trap( 0, "IGNORE" )
66
+
67
+ self.operation.gatget.logger.log("trace", "action_syntax", "Action #{ self.name }#{ multiple_name } exec command syntax : #{ shell_command }" )
68
+
69
+ self.times['init'] ||= Time.now
70
+
71
+ read_stdout, write_stdout = IO.pipe
72
+ read_stderr, write_stderr = IO.pipe
73
+
74
+ pid = fork do
75
+ trap( 0, "IGNORE" )
76
+ read_stdout.close
77
+ read_stderr.close
78
+
79
+ pid_open4, stdin, stdout, stderr = Open4::popen4 "#{ shell_command }"
80
+
81
+ write_stdout.puts stdout.read
82
+ write_stderr.puts stderr.read
83
+
84
+ ignored, status_open4 = Process::waitpid2 pid_open4
85
+ exit status_open4.exitstatus
86
+ end
87
+ trap( 0, trap_save )
88
+
89
+ write_stdout.close
90
+ write_stderr.close
91
+
92
+ result_stdout = read_stdout.read
93
+ result_stderr = read_stderr.read
94
+
95
+ pid, status = Process.wait2(pid)
96
+
97
+ self.output, self.error, self.exit_level = reinterpret_output_and_error(result_stdout, result_stderr, status.exitstatus)
98
+
99
+ self.pid = pid
100
+ self.status = status
101
+ self.times['end'] = Time.now
102
+ end
103
+
104
+
105
+ def set_multiple_childs(multiples_parameters)
106
+ # get multiples values
107
+ multiples_values = {}
108
+ multiples_parameters.each do |parameter|
109
+ values = interpreter_parameter(parameter, self.operation.gatget)
110
+ multiples_values[parameter] = values
111
+ end
112
+
113
+ # all multiple values must have the same size for substitution
114
+ last_multiple_vales_size = multiples_values.values.first.size
115
+ multiples_values.values.each do |values|
116
+ unless values.size == last_multiple_vales_size
117
+ raise GatgetConfigException.new("Multiples values at Action #{ self.name } doesnt have the same size. Substitution cannot be interpreted", "set_multiple_chids")
118
+ end
119
+ last_multiple_vales_size == values.size
120
+ end
121
+
122
+
123
+ unless last_multiple_vales_size > 0
124
+ raise GatgetConfigException.new("Multiples values at Action #{ self.name } are empty", "set_multiple_chids")
125
+ end
126
+
127
+ # create childs objects
128
+ childs = []
129
+ i = 0
130
+ last_multiple_vales_size.times do
131
+ child_multiple_parameters = {}
132
+ multiples_values.each_pair do |parameter, values|
133
+ child_multiple_parameters[parameter] = values[i]
134
+ end
135
+ childs << ShellCommandChild.new(self, child_multiple_parameters)
136
+ i += 1
137
+ end
138
+
139
+ # return child
140
+ childs
141
+ end
142
+
143
+ # Redefine this two methods in your class to clean or reinterpret the output and error
144
+ def reinterpret_output_and_error(output, error, status)
145
+ return output == "\n" ? "" : output,
146
+ error == "\n" ? "" : error, status
147
+ end
148
+
149
+ end
150
+
151
+
152
+ class ShellCommandChild
153
+ include Gat::Interpreter
154
+
155
+ attr_reader :parent
156
+ attr_reader :syntax
157
+ attr_reader :values
158
+ attr_reader :name
159
+
160
+ attr_accessor :syntax
161
+ attr_accessor :arguments
162
+
163
+
164
+ def initialize(parent, values)
165
+ @parent = parent
166
+ @values = values
167
+
168
+
169
+ @syntax = parent.syntax
170
+ @name = "#{ parent.name }*over* #{ values.values.join("_") }"
171
+ end
172
+
173
+ def exec
174
+ # make the substitution of each parameter and exec like other action
175
+ values.each_pair do |parameter_key, parameter_value |
176
+ self.syntax = self.syntax.gsub(/\{\{#{ parameter_key }\}\}/, parameter_value)
177
+ end
178
+
179
+ parse_syntax = interpreter_parameters(self.syntax, self.parent.operation.gatget)
180
+ self.parent.exec(parse_syntax, " *over* #{ values.values.join("_") }")
181
+ end
182
+
183
+ end
184
+ end
185
+ end
data/lib/gat/boot.rb ADDED
@@ -0,0 +1,63 @@
1
+ =begin
2
+
3
+ :file => boot.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
+ # Boot File provides the starting point to execute gatget based script.
25
+ #
26
+ # Boot load required modules && classes for Gat::Base and other gems.
27
+ # Differents exit levels are launched if requires files fails.
28
+ #
29
+ # Gat constants
30
+ GAT_GATGETS = GAT_ROOT + '/gatgets'
31
+ GAT_TEMPLATES = GAT_ROOT + '/templates'
32
+
33
+ # External gems
34
+ gems = [ 'ftools', 'rubygems', 'open4', 'yaml', 'erb', 'rdoc/usage', 'rdoc/code_objects',
35
+ 'rdoc/markup/simple_markup', 'rdoc/markup/simple_markup/to_flow', 'rdoc/ri/ri_formatter',
36
+ 'rdoc/ri/ri_options', 'net/smtp', 'tmail', 'erb' ]
37
+
38
+ # Gat Modules
39
+ modules = [ 'debug', 'help', 'interpreter', 'extends', 'version', 'launcher', 'checks', 'email' ]
40
+
41
+ # Gat Classes
42
+ classes = [ 'exceptions', 'operation', 'dependence/base', 'dependence/program', 'dependence/argument', 'dependence/folder',
43
+ 'action/base.rb', 'action/shell_command.rb', 'action/ruby_method.rb', 'logger' ]
44
+
45
+
46
+ # Build required hash
47
+ load_data = { 'gems' => { 'data' => gems, 'path' => '', 'exit' => 9 },
48
+ 'modules' => { 'data' => modules, 'path' => "#{ GAT_ROOT + '/lib/gat/' }", 'exit' => 10 },
49
+ 'classes' => { 'data' => classes, 'path' => "#{ GAT_ROOT + '/lib/gat/' }", 'exit' => 11 } }
50
+
51
+ # Require all data
52
+ load_data.each_pair do |key, value|
53
+ value['data'].each do |dependency|
54
+ begin
55
+ require value['path'] + dependency
56
+ rescue LoadError => msg
57
+ $stderr.puts "Error while loading #{ key }: #{ msg }"
58
+ $stderr.puts "[ ERROR ] Backtrace \n" + msg.backtrace.join("\n")
59
+ $stderr.puts "\nexit level #{ value['exit'] }"
60
+ exit value['exit']
61
+ end
62
+ end
63
+ end