gaddygaddy 0.1.78

Sign up to get free protection for your applications and to get access to all the features.
data/lib/interval.rb ADDED
@@ -0,0 +1,280 @@
1
+ APPLICATION_NAME = "interval"
2
+
3
+ require 'optparse'
4
+ require 'json'
5
+ require 'logging/logging'
6
+ require 'systemu'
7
+ require 'uri'
8
+
9
+ SENSU_HOST = "127.0.0.1"
10
+
11
+ class Interval
12
+ include Logging
13
+
14
+ ##################################################################
15
+ # Read and parse command line options
16
+ #
17
+ def read_options(argv)
18
+ @options = {}
19
+ optparse = OptionParser.new do|opts|
20
+ opts.banner = "Usage: interval [options] -p <proc_name> -c <command_to_run>"
21
+
22
+ @options[:proc_name] = nil
23
+ opts.on( '-p', '--proc_name <name>', 'Process name to use' ) do |proc_name|
24
+ @options[:proc_name] = proc_name
25
+ end
26
+
27
+ @options[:cmd] = nil
28
+ opts.on( '-c', '--cmd <path>', 'Command to run' ) do |cmd|
29
+ @options[:cmd] = cmd
30
+ end
31
+
32
+ opts.on( '-u', '--uri_cmd <path>', 'Command to run (URI-encoded)' ) do |ucmd|
33
+ @options[:cmd] = URI.unescape(ucmd)
34
+ end
35
+
36
+ @options[:config_name] = nil
37
+ opts.on( '-C', '--config_name <name>', 'Config name to use' ) do |config_name|
38
+ @options[:config_name] = config_name
39
+ end
40
+
41
+ @options[:home] = nil
42
+ opts.on( '-h', '--home <home>', 'Home directory of application' ) do |home|
43
+ @options[:home] = home
44
+ end
45
+
46
+ @options[:log_file] = nil
47
+ opts.on( '-l', '--logfile FILE', 'Write log to FILE, defaults to STDOUT' ) do |file|
48
+ @options[:log_file] = file
49
+ end
50
+
51
+ @options[:log_level] = 'info'
52
+ opts.on( '-L', '--log_level level', 'Set the log level (debug, info, warn, error, fatal)' ) do| level|
53
+ @options[:log_level] = level
54
+ end
55
+
56
+ @options[:count] = nil
57
+ opts.on( '-n', '--num <count>', 'Run the command <count> times and then exit (use for testing)' ) do |count|
58
+ @options[:count] = count.to_i
59
+ end
60
+
61
+ @options[:fail_on_error] = false
62
+ opts.on( '-f', '--fail_on_error', 'Abort if the program fails' ) do
63
+ @options[:fail_on_error] = true
64
+ end
65
+
66
+ @options[:sensu_enabled] = false
67
+ opts.on( '-z', '--sensu', 'Do report status to Sensu' ) do
68
+ @options[:sensu_enabled] = true
69
+ end
70
+
71
+ @options[:sensu_port] = 3030
72
+ opts.on( '--sensu_port <port>', Integer, 'Port to talk to sensu on' ) do |port|
73
+ @options[:sensu_port] = port
74
+ end
75
+
76
+ @options[:status_file] = nil
77
+ opts.on( '-s', '--status_file <status>', 'File to write last run status to' ) do |status|
78
+ @options[:status_file] = status
79
+ end
80
+
81
+ @options[:interval] = nil
82
+ opts.on( '-i', '--interval <interval>', 'Time between runs of program (seconds if no unit is specified)' ) do |interval|
83
+ @options[:interval] = interval
84
+ end
85
+
86
+ @options[:time_stamp] = nil
87
+ opts.on( '-t', '--time <time>', 'Run command at a specific time each day, could be comma separated. Format HHMM. Example 1430,0230 will run the command at 14:30 and 02:30 each day' ) do |time|
88
+ @options[:time_stamp] = time.split(",")
89
+ end
90
+
91
+ opts.on_tail("-h", "--help", "Show this message") do
92
+ puts opts
93
+ exit
94
+ end
95
+ end
96
+
97
+ begin
98
+ optparse.parse!(argv)
99
+ if @options[:config_name].nil?
100
+ @options[:config_name] = @options[:proc_name]
101
+ end
102
+ mandatory = [:proc_name, :cmd]
103
+ missing = mandatory.select{ |param| @options[param].nil? }
104
+ unless missing.empty?
105
+ STDERR.puts "Missing options: #{missing.join(', ')}"
106
+ STDERR.puts optparse
107
+ exit 1
108
+ end
109
+ rescue OptionParser::InvalidOption, OptionParser::MissingArgument #
110
+ STDERR.puts $!.to_s # Friendly output when parsing fails
111
+ STDERR.puts optparse #
112
+ exit 1 #
113
+ end
114
+ end
115
+
116
+ ##################################################################
117
+ # Parse a time expression
118
+ #
119
+ # The argument should be in one of the following forms
120
+ # <number> - parsed as seconds
121
+ # <number>s - parsed as seconds
122
+ # <number>m - parsed as minutes
123
+ # <number>h - parsed as hours
124
+ #
125
+ # @param s [String] String to parse
126
+ #
127
+ # return [Numeric] number of seconds time represents
128
+
129
+ def parse_time(s)
130
+ case s
131
+ when /^\d+s?$/
132
+ s.to_i
133
+ when /^\d+m$/
134
+ s.to_i * 60
135
+ when /^\d+h$/
136
+ s.to_i * 60 * 60
137
+ else
138
+ -1
139
+ end
140
+ end
141
+
142
+ ##################################################################
143
+ # Store status on disk
144
+ def store_status(exit_code)
145
+ if @options[:status_file]
146
+ File.open(@options[:status_file], 'w') do |f| f.puts("result=#{exit_code}") end
147
+ end
148
+ end
149
+
150
+ ##################################################################
151
+ # Fail, exit with an error message
152
+ def my_fail(msg)
153
+ logger.fatal msg if logger
154
+ STDERR.puts msg
155
+ send_to_sensu(1, "Error running interval for #{@options[:proc_name]}, #{msg}")
156
+ store_status 1
157
+ exit 1
158
+ end
159
+
160
+ ###################################################################
161
+ # Send message to sensu
162
+ #
163
+ def send_to_sensu(status, message)
164
+ if @options[:sensu_enabled]
165
+ report = {
166
+ :name => "interval_error_#{@options[:proc_name]}",
167
+ :output => "",
168
+ :status => status
169
+ }
170
+ if status != 0
171
+ report[:output] = "Failed to run #{@options[:proc_name]} #{message}"
172
+ end
173
+
174
+ begin
175
+ s = TCPSocket.open(SENSU_HOST, @options[:sensu_port])
176
+ s.print JSON.generate(report)
177
+ s.close
178
+ rescue Exception => e
179
+ logger.error "Failed to send report to sensu: #{e.message}"
180
+ end
181
+ end
182
+ end
183
+
184
+ def get_prop(option_name)
185
+ prop_value = nil
186
+ if @options[option_name]
187
+ prop_value = @options[option_name]
188
+ end
189
+ logger.debug "Found value #{prop_value} for #{option_name.to_s}"
190
+ prop_value
191
+ end
192
+
193
+ def run
194
+ read_options(ARGV)
195
+
196
+ # Check binary
197
+ unless File.executable?(@options[:cmd].split[0])
198
+ my_fail "Specified binary '#{@options[:cmd]}' does not exist or is not executable"
199
+ end
200
+
201
+ set_log_level @options[:log_level]
202
+ set_log_file @options[:log_file] if @options[:log_file]
203
+
204
+ if @options[:home]
205
+ Dir.chdir(@options[:home])
206
+ end
207
+
208
+ # Get properties
209
+ conf_name = @options[:config_name] ? @options[:config_name] : @options[:proc_name]
210
+
211
+ begin
212
+ interval_in = get_prop :interval
213
+ if interval_in
214
+ interval = parse_time interval_in
215
+ logger.info "Using an run interval of #{interval} seconds"
216
+ if interval < 1
217
+ my_fail "Illegal interval #{interval} given for property #{conf_name}.run.interval"
218
+ end
219
+
220
+ else
221
+ time_stamp = get_prop :time_stamp
222
+ raise "Could not found interval or time_stamp option, one of those is needed" unless time_stamp
223
+ logger.info "Will run at time stamp #{time_stamp.join(",")}"
224
+ end
225
+ rescue StandardError => e
226
+ puts e.message
227
+ my_fail "Did not find config value for #{conf_name}"
228
+ end
229
+
230
+
231
+ logger.info "Starting interval #{@options.inspect}"
232
+
233
+ store_status 0
234
+
235
+ count = 0
236
+ first = true
237
+ loop do
238
+ unless time_stamp && first
239
+ count = count+1
240
+ logger.info "Launching[#{count}]: #{@options[:cmd]}"
241
+ result, stdout, stderr = systemu @options[:cmd]
242
+ store_status result.exitstatus
243
+ if result != 0
244
+ logger.error "Failed to run #{@options[:cmd]} (exit code #{result})"
245
+ logger.error "Stdout: #{stdout.strip}" if stdout.length > 0
246
+ logger.error "Stderr: #{stderr.strip}" if stderr.length > 0
247
+ send_to_sensu(1, "Result is #{result}. Stderr is: #{stderr}, stdout is #{stdout}")
248
+ if @options[:fail_on_error]
249
+ exit result
250
+ end
251
+ else
252
+ logger.info "Command completed successfully"
253
+ logger.info "Stdout: #{stdout.strip}" if stdout.length > 0
254
+ send_to_sensu(0, "")
255
+ end
256
+ end
257
+ first = false
258
+
259
+ if @options[:count] && count >= @options[:count]
260
+ exit 0
261
+ end
262
+ if time_stamp
263
+ diff = []
264
+ time_stamp.each do |time|
265
+ current = Time.now.strftime("%H%M%S")
266
+ diff_time = ((time[0..1].to_i * 60 + time[2..3].to_i) - (current[0..1].to_i * 60 + current[2..3].to_i))*60 - current[4..5].to_i
267
+ diff_time += 24*60*60 if diff_time <= 0
268
+ diff << diff_time
269
+ end
270
+ logger.debug "sleep for #{diff.min + 1} seconds"
271
+ sleep diff.min + 1
272
+ else
273
+ logger.debug "sleep for #{interval} seconds"
274
+ sleep interval
275
+ end
276
+ end
277
+ end
278
+
279
+ end
280
+
@@ -0,0 +1,62 @@
1
+ #
2
+ # Name:
3
+ # logging.rb
4
+ #
5
+ # Created by: GaddyGaddy
6
+ #
7
+ # Description:
8
+ #
9
+ #
10
+ #
11
+ # Copyright (c) 2013 GaddyGaddy
12
+ #
13
+ # All rights reserved.
14
+ #
15
+
16
+ require 'log4r'
17
+ require 'log4r/outputter/datefileoutputter'
18
+ require 'log4r/yamlconfigurator'
19
+
20
+ module Logging
21
+ # This is the magical bit that gets mixed into your classes
22
+ @@log_conf = const_defined?(:APPLICATION_NAME) ? APPLICATION_NAME : "default"
23
+
24
+ def logger
25
+ Logging.logger
26
+ end
27
+
28
+ def set_log_level(level_str)
29
+ logger.level = (Log4r::Log4rConfig::LogLevels.index level_str.upcase) + 1
30
+ end
31
+
32
+ def set_log_file(new_filename)
33
+ format = Log4r::PatternFormatter.new(:pattern => "[%5l] %d :: %m", :date_pattern => '%y%m%d %H:%M:%S')
34
+ dir_name = File.dirname(new_filename)
35
+ file_name = File.basename(new_filename)
36
+ logger.outputters << Log4r::DateFileOutputter.new('log_file', :filename => file_name, :dirname => dir_name, :formatter => format, :date_pattern => '%Y%m%d')
37
+ end
38
+
39
+ def self.set_log_conf log_conf
40
+ @@log_conf = log_conf
41
+ end
42
+
43
+ # create a new log4r logger with config
44
+
45
+ def self.create_logger
46
+ log_cfg = Log4r::YamlConfigurator
47
+ conf_file = File.join(File.dirname(__FILE__), "..", "..", "conf","log4r.yml")
48
+ log_cfg.load_yaml_file(conf_file)
49
+
50
+ # app logger
51
+ new_logger = Log4r::Logger[@@log_conf]
52
+ raise "Missing logger config #{@@log_conf} in log config file #{conf_file}" unless new_logger
53
+ new_logger.level = Log4r::INFO
54
+ new_logger.info "Log initiated"
55
+ new_logger
56
+ end
57
+
58
+ # Global, memoized, lazy initialized instance of a logger
59
+ def self.logger
60
+ @logger ||= create_logger
61
+ end
62
+ end
@@ -0,0 +1,34 @@
1
+ #
2
+ # Name:
3
+ # hash.rb
4
+ #
5
+ # Created by: GaddyGaddy
6
+ #
7
+ # Description:
8
+ #
9
+ #
10
+ #
11
+ # Copyright (c) 2013 GaddyGaddy
12
+ #
13
+ # All rights reserved.
14
+ #
15
+
16
+ class Hash
17
+ # Return a new hash with all keys converted to symbols, as long as
18
+ # they respond to +to_sym+.
19
+ #
20
+ # { 'name' => 'Rob', 'years' => '28' }.symbolize_keys
21
+ # #=> { :name => "Rob", :years => "28" }
22
+ def symbolize_keys
23
+ dup.symbolize_keys!
24
+ end
25
+
26
+ # Destructively convert all keys to symbols, as long as they respond
27
+ # to +to_sym+. Same as +symbolize_keys+, but modifies +self+.
28
+ def symbolize_keys!
29
+ keys.each do |key|
30
+ self[(key.to_sym rescue key) || key] = delete(key)
31
+ end
32
+ self
33
+ end
34
+ end
@@ -0,0 +1,52 @@
1
+ #
2
+ # Name:
3
+ # requests.rb
4
+ #
5
+ # Created by: GaddyGaddy
6
+ #
7
+ # Description:
8
+ #
9
+ #
10
+ #
11
+ # Copyright (c) 2013 GaddyGaddy
12
+ #
13
+ # All rights reserved.
14
+ #
15
+ require 'cgi'
16
+
17
+ require_relative '../utils/retriable'
18
+ require_relative '../logging/logging'
19
+ class Request
20
+ extend Logging
21
+ extend Retriable
22
+
23
+ # Get a base url for accessing the client service
24
+ # TODO Change this to https but we need a certificate for that
25
+ def self.get_base_url(host)
26
+ url = host
27
+ url = "http://" + url unless url[0..3] == "http"
28
+ url
29
+ end
30
+
31
+
32
+ #
33
+ # Will do a request
34
+ # path will be evaluated so there could be parameters in that one and then use '' for the string
35
+ # to have the parameters evaluated in this function
36
+ #
37
+ def self.client_service_get(host, path)
38
+ url = get_base_url(host) + path
39
+ logger.debug "Will request url #{url}"
40
+ result = with_retries(:limit => 10, :sleep=> 5) { RestClient.get url }
41
+ result_json = JSON.parse(result)
42
+ logger.debug "The result of the request is #{result.inspect}"
43
+ result_json
44
+ end
45
+
46
+ def self.client_service_post(url, param)
47
+ logger.debug "Will request url #{url}"
48
+ result = with_retries(:limit => 10, :sleep=> 5) { RestClient.post url, param }
49
+ JSON.parse(result)
50
+ end
51
+
52
+ end
@@ -0,0 +1,63 @@
1
+ #
2
+ # Name:
3
+ # retriable.rb
4
+ #
5
+ # Created by: GaddyGaddy
6
+ #
7
+ # Description:
8
+ #
9
+ #
10
+ #
11
+
12
+ module Retriable
13
+
14
+ @@test_mode = false
15
+
16
+ # This will catch any exception and retry twice (three tries total):
17
+ # with_retries { ... }
18
+ #
19
+ # This will catch any exception and retry four times (five tries total):
20
+ # with_retries(:limit => 5) { ... }
21
+ #
22
+ # This will catch a specific exception and retry once (two tries total):
23
+ # with_retries(Some::Error, :limit => 2) { ... }
24
+ #
25
+ # You can also sleep inbetween tries. This is helpful if you're hoping
26
+ # that some external service recovers from its issues.
27
+ # with_retries(Service::Error, :sleep => 1) { ... }
28
+ #
29
+ def with_retries(*args, &block)
30
+
31
+ options = extract_options args
32
+ exceptions = args
33
+
34
+ options[:limit] ||= 3
35
+ options[:limit] = 0 if @@test_mode
36
+ options[:sleep] ||= 0
37
+ exceptions = [Exception] if exceptions.empty?
38
+
39
+ retried = 0
40
+ begin
41
+ yield
42
+ rescue *exceptions => e
43
+ logger.warn "Could not do command, will retry. Error message is #{e.inspect.to_s}"
44
+ if retried + 1 < options[:limit]
45
+ retried += 1
46
+ sleep options[:sleep]
47
+ retry
48
+ else
49
+ raise e
50
+ end
51
+ end
52
+ end
53
+
54
+ def extract_options(array)
55
+ array.last.is_a?(::Hash) ? array.pop : {}
56
+ end
57
+
58
+ def self.set_test_mode
59
+ @@test_mode = true
60
+ end
61
+
62
+
63
+ end
data/lib/utils/run.rb ADDED
@@ -0,0 +1,20 @@
1
+ #
2
+ # Name:
3
+ # run.rb
4
+ #
5
+ # Created by: GaddyGaddy
6
+ #
7
+ # Description:
8
+ #
9
+ #
10
+ #
11
+ # Copyright (c) 2013 GaddyGaddy
12
+ #
13
+ # All rights reserved.
14
+ #
15
+
16
+
17
+ def run_cmd(cmd)
18
+ status, stdout, stderr = systemu cmd
19
+ raise "Could not run command: #{cmd}, stdout is #{stdout}, error message is #{stderr}" if status != 0
20
+ end
data/locales/en.yml ADDED
@@ -0,0 +1,24 @@
1
+ en:
2
+ event:
3
+ converge:
4
+ chef_failed: ! 'Installation of gaddy failed. Please contact the support. Installation failed at %s. Reason: %s and %s'
5
+ chef_failed_v1: ! 'Installation of gaddy failed. Please contact the support. Installation failed at %s. Reason: %s'
6
+ ok: The device has been successful installed
7
+ repair: Repair of installation done.
8
+ usb_drive_missing: A USB drive is not connected. It should be connected as %s
9
+ init:
10
+ config_updated: The device has been succesfully initiated, installation will now start
11
+ connected: The device is successful connected to internet
12
+ install:
13
+ installation_begin: Installation of gApp %s has started
14
+ installation_failed: Installation of gApp %s failed. The gApp is not running
15
+ installation_finished: Installation of gApp %s is finished
16
+ log:
17
+ error: Error in log %s message %s
18
+ not_running: ! '%s not working. '
19
+ not_running_v1: gApp is not running
20
+ ok: Running normally
21
+ spotify_config_not_ok: There is a problem with the Spotify configuration. Try to update username and password
22
+ vpn_proxy:
23
+ missing_user_or_password: Missing user name or password for vpn_proxy, check gApp
24
+ no_connection: Could not connect to the VPN server, check configuration
data/locales/sv.yml ADDED
@@ -0,0 +1,11 @@
1
+ sv:
2
+ event:
3
+ converge:
4
+ chef_failed:
5
+ ok:
6
+ init:
7
+ config_updated:
8
+ connected:
9
+ install:
10
+ installation_begin:
11
+ installation_finished: