gat 0.2.8

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